From b645e20ba765f735f4b64502f144d4ba1e50cbef Mon Sep 17 00:00:00 2001 From: Simon Schubert Date: Fri, 13 Apr 2007 12:05:44 +0000 Subject: [PATCH] Import binutils-2.17. --- contrib/binutils-2.17/COPYING | 340 + contrib/binutils-2.17/COPYING.LIB | 482 + contrib/binutils-2.17/README | 47 + contrib/binutils-2.17/bfd/COPYING | 340 + contrib/binutils-2.17/bfd/PORTING | 83 + contrib/binutils-2.17/bfd/README | 49 + contrib/binutils-2.17/bfd/archive.c | 2157 +++++ contrib/binutils-2.17/bfd/archive64.c | 240 + contrib/binutils-2.17/bfd/archures.c | 1209 +++ contrib/binutils-2.17/bfd/bfd-in.h | 901 ++ contrib/binutils-2.17/bfd/bfd-in2.h | 5140 ++++++++++ contrib/binutils-2.17/bfd/bfd.c | 1515 +++ contrib/binutils-2.17/bfd/bfdio.c | 447 + contrib/binutils-2.17/bfd/binary.c | 378 + contrib/binutils-2.17/bfd/cache.c | 532 ++ contrib/binutils-2.17/bfd/coffgen.c | 2326 +++++ contrib/binutils-2.17/bfd/config.bfd | 1445 +++ contrib/binutils-2.17/bfd/config.in | 375 + contrib/binutils-2.17/bfd/corefile.c | 165 + contrib/binutils-2.17/bfd/cpu-i386.c | 103 + contrib/binutils-2.17/bfd/doc/aoutx.texi | 213 + contrib/binutils-2.17/bfd/doc/archive.texi | 99 + contrib/binutils-2.17/bfd/doc/archures.texi | 585 ++ contrib/binutils-2.17/bfd/doc/bfd.texinfo | 336 + contrib/binutils-2.17/bfd/doc/bfdint.texi | 1890 ++++ contrib/binutils-2.17/bfd/doc/bfdio.texi | 72 + contrib/binutils-2.17/bfd/doc/bfdsumm.texi | 148 + contrib/binutils-2.17/bfd/doc/bfdt.texi | 721 ++ contrib/binutils-2.17/bfd/doc/bfdwin.texi | 2 + contrib/binutils-2.17/bfd/doc/cache.texi | 65 + contrib/binutils-2.17/bfd/doc/coffcode.texi | 608 ++ contrib/binutils-2.17/bfd/doc/core.texi | 60 + contrib/binutils-2.17/bfd/doc/elf.texi | 22 + contrib/binutils-2.17/bfd/doc/elfcode.texi | 0 contrib/binutils-2.17/bfd/doc/format.texi | 112 + contrib/binutils-2.17/bfd/doc/hash.texi | 247 + contrib/binutils-2.17/bfd/doc/init.texi | 16 + contrib/binutils-2.17/bfd/doc/libbfd.texi | 179 + contrib/binutils-2.17/bfd/doc/linker.texi | 380 + contrib/binutils-2.17/bfd/doc/mmo.texi | 365 + contrib/binutils-2.17/bfd/doc/opncls.texi | 365 + contrib/binutils-2.17/bfd/doc/reloc.texi | 2494 +++++ contrib/binutils-2.17/bfd/doc/section.texi | 989 ++ contrib/binutils-2.17/bfd/doc/syms.texi | 461 + contrib/binutils-2.17/bfd/doc/targets.texi | 551 ++ contrib/binutils-2.17/bfd/dwarf1.c | 556 ++ contrib/binutils-2.17/bfd/dwarf2.c | 2798 ++++++ contrib/binutils-2.17/bfd/efi-app-ia32.c | 34 + contrib/binutils-2.17/bfd/efi-app-ia64.c | 35 + contrib/binutils-2.17/bfd/elf-bfd.h | 1955 ++++ contrib/binutils-2.17/bfd/elf-eh-frame.c | 1424 +++ contrib/binutils-2.17/bfd/elf-strtab.c | 390 + contrib/binutils-2.17/bfd/elf-vxworks.c | 213 + contrib/binutils-2.17/bfd/elf-vxworks.h | 35 + contrib/binutils-2.17/bfd/elf.c | 8740 +++++++++++++++++ contrib/binutils-2.17/bfd/elf32-i386.c | 4004 ++++++++ contrib/binutils-2.17/bfd/elf32.c | 22 + contrib/binutils-2.17/bfd/elf64-gen.c | 101 + contrib/binutils-2.17/bfd/elf64-x86-64.c | 3689 ++++++++ contrib/binutils-2.17/bfd/elf64.c | 22 + contrib/binutils-2.17/bfd/elfcode.h | 1834 ++++ contrib/binutils-2.17/bfd/elfcore.h | 251 + contrib/binutils-2.17/bfd/elflink.c | 9943 ++++++++++++++++++++ contrib/binutils-2.17/bfd/elfxx-target.h | 853 ++ contrib/binutils-2.17/bfd/format.c | 446 + contrib/binutils-2.17/bfd/genlink.h | 109 + contrib/binutils-2.17/bfd/hash.c | 736 ++ contrib/binutils-2.17/bfd/ihex.c | 996 ++ contrib/binutils-2.17/bfd/init.c | 54 + contrib/binutils-2.17/bfd/libaout.h | 685 ++ contrib/binutils-2.17/bfd/libbfd-in.h | 728 ++ contrib/binutils-2.17/bfd/libbfd.c | 1045 ++ contrib/binutils-2.17/bfd/libbfd.h | 1909 ++++ contrib/binutils-2.17/bfd/libcoff.h | 935 ++ contrib/binutils-2.17/bfd/libecoff.h | 337 + contrib/binutils-2.17/bfd/linker.c | 3108 ++++++ contrib/binutils-2.17/bfd/merge.c | 873 ++ contrib/binutils-2.17/bfd/opncls.c | 1452 +++ contrib/binutils-2.17/bfd/reloc.c | 4939 ++++++++++ contrib/binutils-2.17/bfd/section.c | 1521 +++ contrib/binutils-2.17/bfd/simple.c | 257 + contrib/binutils-2.17/bfd/srec.c | 1322 +++ contrib/binutils-2.17/bfd/stab-syms.c | 58 + contrib/binutils-2.17/bfd/stabs.c | 784 ++ contrib/binutils-2.17/bfd/syms.c | 1391 +++ contrib/binutils-2.17/bfd/sysdep.h | 201 + contrib/binutils-2.17/bfd/targets.c | 1425 +++ contrib/binutils-2.17/bfd/targmatch.sed | 33 + contrib/binutils-2.17/bfd/tekhex.c | 1004 ++ contrib/binutils-2.17/bfd/version.h | 3 + contrib/binutils-2.17/binutils/addr2line.c | 407 + contrib/binutils-2.17/binutils/ar.c | 1263 +++ contrib/binutils-2.17/binutils/arlex.c | 1856 ++++ contrib/binutils-2.17/binutils/arparse.c | 1605 ++++ contrib/binutils-2.17/binutils/arparse.h | 92 + contrib/binutils-2.17/binutils/arsup.c | 478 + contrib/binutils-2.17/binutils/arsup.h | 62 + contrib/binutils-2.17/binutils/binemul.c | 105 + contrib/binutils-2.17/binutils/binemul.h | 61 + contrib/binutils-2.17/binutils/bucomm.c | 513 + contrib/binutils-2.17/binutils/bucomm.h | 226 + contrib/binutils-2.17/binutils/budbg.h | 58 + contrib/binutils-2.17/binutils/budemang.c | 100 + contrib/binutils-2.17/binutils/budemang.h | 25 + contrib/binutils-2.17/binutils/config.in | 267 + contrib/binutils-2.17/binutils/debug.c | 3373 +++++++ contrib/binutils-2.17/binutils/debug.h | 792 ++ contrib/binutils-2.17/binutils/doc/addr2line.1 | 265 + contrib/binutils-2.17/binutils/doc/ar.1 | 390 + contrib/binutils-2.17/binutils/doc/binutils.texi | 3907 ++++++++ contrib/binutils-2.17/binutils/doc/config.texi | 2 + contrib/binutils-2.17/binutils/doc/fdl.texi | 368 + contrib/binutils-2.17/binutils/doc/nm.1 | 449 + contrib/binutils-2.17/binutils/doc/objcopy.1 | 795 ++ contrib/binutils-2.17/binutils/doc/objdump.1 | 634 ++ contrib/binutils-2.17/binutils/doc/ranlib.1 | 188 + contrib/binutils-2.17/binutils/doc/readelf.1 | 376 + contrib/binutils-2.17/binutils/doc/size.1 | 263 + contrib/binutils-2.17/binutils/doc/strings.1 | 249 + contrib/binutils-2.17/binutils/doc/strip.1 | 383 + contrib/binutils-2.17/binutils/dwarf.c | 3732 ++++++++ contrib/binutils-2.17/binutils/dwarf.h | 122 + contrib/binutils-2.17/binutils/emul_vanilla.c | 29 + contrib/binutils-2.17/binutils/filemode.c | 248 + contrib/binutils-2.17/binutils/ieee.c | 7399 +++++++++++++++ contrib/binutils-2.17/binutils/is-ranlib.c | 3 + contrib/binutils-2.17/binutils/is-strip.c | 4 + contrib/binutils-2.17/binutils/nm.c | 1639 ++++ contrib/binutils-2.17/binutils/not-ranlib.c | 3 + contrib/binutils-2.17/binutils/not-strip.c | 4 + contrib/binutils-2.17/binutils/objcopy.c | 3301 +++++++ contrib/binutils-2.17/binutils/objdump.c | 3188 +++++++ contrib/binutils-2.17/binutils/prdbg.c | 2795 ++++++ contrib/binutils-2.17/binutils/rdcoff.c | 874 ++ contrib/binutils-2.17/binutils/rddbg.c | 447 + contrib/binutils-2.17/binutils/readelf.c | 9362 ++++++++++++++++++ contrib/binutils-2.17/binutils/rename.c | 219 + contrib/binutils-2.17/binutils/size.c | 552 ++ contrib/binutils-2.17/binutils/stabs.c | 5399 +++++++++++ contrib/binutils-2.17/binutils/strings.c | 727 ++ contrib/binutils-2.17/binutils/unwind-ia64.c | 1082 +++ contrib/binutils-2.17/binutils/unwind-ia64.h | 31 + contrib/binutils-2.17/binutils/version.c | 40 + contrib/binutils-2.17/binutils/wrstabs.c | 2274 +++++ contrib/binutils-2.17/gas/CONTRIBUTORS | 110 + contrib/binutils-2.17/gas/COPYING | 340 + contrib/binutils-2.17/gas/README | 164 + contrib/binutils-2.17/gas/app.c | 1409 +++ contrib/binutils-2.17/gas/as.c | 1207 +++ contrib/binutils-2.17/gas/as.h | 665 ++ contrib/binutils-2.17/gas/asintl.h | 52 + contrib/binutils-2.17/gas/atof-generic.c | 616 ++ contrib/binutils-2.17/gas/bignum.h | 41 + contrib/binutils-2.17/gas/bit_fix.h | 48 + contrib/binutils-2.17/gas/cond.c | 576 ++ contrib/binutils-2.17/gas/config.in | 318 + contrib/binutils-2.17/gas/config/atof-ieee.c | 700 ++ contrib/binutils-2.17/gas/config/obj-elf.c | 2265 +++++ contrib/binutils-2.17/gas/config/obj-elf.h | 258 + contrib/binutils-2.17/gas/config/tc-i386.c | 7338 +++++++++++++++ contrib/binutils-2.17/gas/config/tc-i386.h | 514 + contrib/binutils-2.17/gas/depend.c | 206 + contrib/binutils-2.17/gas/doc/as.1 | 1109 +++ contrib/binutils-2.17/gas/doc/as.texinfo | 6760 +++++++++++++ contrib/binutils-2.17/gas/doc/asconfig.texi | 90 + contrib/binutils-2.17/gas/doc/c-alpha.texi | 472 + contrib/binutils-2.17/gas/doc/c-arc.texi | 333 + contrib/binutils-2.17/gas/doc/c-arm.texi | 634 ++ contrib/binutils-2.17/gas/doc/c-bfin.texi | 187 + contrib/binutils-2.17/gas/doc/c-cris.texi | 410 + contrib/binutils-2.17/gas/doc/c-d10v.texi | 257 + contrib/binutils-2.17/gas/doc/c-d30v.texi | 292 + contrib/binutils-2.17/gas/doc/c-h8300.texi | 357 + contrib/binutils-2.17/gas/doc/c-hppa.texi | 301 + contrib/binutils-2.17/gas/doc/c-i370.texi | 200 + contrib/binutils-2.17/gas/doc/c-i386.texi | 767 ++ contrib/binutils-2.17/gas/doc/c-i860.texi | 172 + contrib/binutils-2.17/gas/doc/c-i960.texi | 299 + contrib/binutils-2.17/gas/doc/c-ia64.texi | 187 + contrib/binutils-2.17/gas/doc/c-ip2k.texi | 46 + contrib/binutils-2.17/gas/doc/c-m32c.texi | 116 + contrib/binutils-2.17/gas/doc/c-m32r.texi | 358 + contrib/binutils-2.17/gas/doc/c-m68hc11.texi | 442 + contrib/binutils-2.17/gas/doc/c-m68k.texi | 621 ++ contrib/binutils-2.17/gas/doc/c-mips.texi | 482 + contrib/binutils-2.17/gas/doc/c-mmix.texi | 586 ++ contrib/binutils-2.17/gas/doc/c-msp430.texi | 321 + contrib/binutils-2.17/gas/doc/c-pdp11.texi | 354 + contrib/binutils-2.17/gas/doc/c-pj.texi | 28 + contrib/binutils-2.17/gas/doc/c-ppc.texi | 132 + contrib/binutils-2.17/gas/doc/c-sh.texi | 331 + contrib/binutils-2.17/gas/doc/c-sh64.texi | 215 + contrib/binutils-2.17/gas/doc/c-sparc.texi | 195 + contrib/binutils-2.17/gas/doc/c-tic54x.texi | 767 ++ contrib/binutils-2.17/gas/doc/c-v850.texi | 396 + contrib/binutils-2.17/gas/doc/c-vax.texi | 358 + contrib/binutils-2.17/gas/doc/c-xtensa.texi | 753 ++ contrib/binutils-2.17/gas/doc/c-z80.texi | 257 + contrib/binutils-2.17/gas/doc/c-z8k.texi | 400 + contrib/binutils-2.17/gas/doc/fdl.texi | 367 + contrib/binutils-2.17/gas/doc/gasver.texi | 1 + contrib/binutils-2.17/gas/dw2gencfi.c | 1085 +++ contrib/binutils-2.17/gas/dw2gencfi.h | 52 + contrib/binutils-2.17/gas/dwarf2dbg.c | 1574 ++++ contrib/binutils-2.17/gas/dwarf2dbg.h | 102 + contrib/binutils-2.17/gas/ecoff.c | 5235 +++++++++++ contrib/binutils-2.17/gas/ecoff.h | 111 + contrib/binutils-2.17/gas/ehopt.c | 532 ++ contrib/binutils-2.17/gas/expr.c | 2188 +++++ contrib/binutils-2.17/gas/expr.h | 180 + contrib/binutils-2.17/gas/flonum-copy.c | 71 + contrib/binutils-2.17/gas/flonum-konst.c | 228 + contrib/binutils-2.17/gas/flonum-mult.c | 188 + contrib/binutils-2.17/gas/flonum.h | 102 + contrib/binutils-2.17/gas/frags.c | 438 + contrib/binutils-2.17/gas/frags.h | 153 + contrib/binutils-2.17/gas/hash.c | 616 ++ contrib/binutils-2.17/gas/hash.h | 88 + contrib/binutils-2.17/gas/input-file.c | 263 + contrib/binutils-2.17/gas/input-file.h | 65 + contrib/binutils-2.17/gas/input-scrub.c | 477 + contrib/binutils-2.17/gas/itbl-lex.c | 1713 ++++ contrib/binutils-2.17/gas/itbl-lex.h | 23 + contrib/binutils-2.17/gas/itbl-ops.c | 890 ++ contrib/binutils-2.17/gas/itbl-ops.h | 108 + contrib/binutils-2.17/gas/itbl-parse.c | 1842 ++++ contrib/binutils-2.17/gas/itbl-parse.h | 77 + contrib/binutils-2.17/gas/listing.c | 1335 +++ contrib/binutils-2.17/gas/listing.h | 67 + contrib/binutils-2.17/gas/literal.c | 95 + contrib/binutils-2.17/gas/macro.c | 1407 +++ contrib/binutils-2.17/gas/macro.h | 97 + contrib/binutils-2.17/gas/messages.c | 537 ++ contrib/binutils-2.17/gas/obj.h | 85 + contrib/binutils-2.17/gas/output-file.c | 67 + contrib/binutils-2.17/gas/output-file.h | 26 + contrib/binutils-2.17/gas/read.c | 5450 +++++++++++ contrib/binutils-2.17/gas/read.h | 188 + contrib/binutils-2.17/gas/sb.c | 254 + contrib/binutils-2.17/gas/sb.h | 96 + contrib/binutils-2.17/gas/stabs.c | 703 ++ contrib/binutils-2.17/gas/struc-symbol.h | 148 + contrib/binutils-2.17/gas/subsegs.c | 446 + contrib/binutils-2.17/gas/subsegs.h | 115 + contrib/binutils-2.17/gas/symbols.c | 2822 ++++++ contrib/binutils-2.17/gas/symbols.h | 206 + contrib/binutils-2.17/gas/tc.h | 76 + contrib/binutils-2.17/gas/write.c | 2413 +++++ contrib/binutils-2.17/gas/write.h | 170 + contrib/binutils-2.17/include/COPYING | 340 + contrib/binutils-2.17/include/ansidecl.h | 371 + contrib/binutils-2.17/include/aout/aout64.h | 519 + contrib/binutils-2.17/include/aout/ar.h | 52 + contrib/binutils-2.17/include/aout/ranlib.h | 62 + contrib/binutils-2.17/include/aout/stab.def | 271 + contrib/binutils-2.17/include/aout/stab_gnu.h | 54 + contrib/binutils-2.17/include/bfdlink.h | 718 ++ contrib/binutils-2.17/include/bin-bugs.h | 3 + contrib/binutils-2.17/include/coff/ecoff.h | 410 + contrib/binutils-2.17/include/coff/internal.h | 752 ++ contrib/binutils-2.17/include/coff/sym.h | 484 + contrib/binutils-2.17/include/demangle.h | 536 ++ contrib/binutils-2.17/include/dis-asm.h | 339 + contrib/binutils-2.17/include/dyn-string.h | 60 + contrib/binutils-2.17/include/elf/alpha.h | 130 + contrib/binutils-2.17/include/elf/arc.h | 56 + contrib/binutils-2.17/include/elf/arm.h | 285 + contrib/binutils-2.17/include/elf/avr.h | 67 + contrib/binutils-2.17/include/elf/bfin.h | 92 + contrib/binutils-2.17/include/elf/common.h | 767 ++ contrib/binutils-2.17/include/elf/cris.h | 113 + contrib/binutils-2.17/include/elf/crx.h | 53 + contrib/binutils-2.17/include/elf/d10v.h | 38 + contrib/binutils-2.17/include/elf/d30v.h | 42 + contrib/binutils-2.17/include/elf/dlx.h | 53 + contrib/binutils-2.17/include/elf/dwarf.h | 324 + contrib/binutils-2.17/include/elf/dwarf2.h | 836 ++ contrib/binutils-2.17/include/elf/external.h | 279 + contrib/binutils-2.17/include/elf/fr30.h | 42 + contrib/binutils-2.17/include/elf/frv.h | 130 + contrib/binutils-2.17/include/elf/h8.h | 100 + contrib/binutils-2.17/include/elf/hppa.h | 614 ++ contrib/binutils-2.17/include/elf/i370.h | 68 + contrib/binutils-2.17/include/elf/i386.h | 78 + contrib/binutils-2.17/include/elf/i860.h | 66 + contrib/binutils-2.17/include/elf/i960.h | 37 + contrib/binutils-2.17/include/elf/ia64.h | 219 + contrib/binutils-2.17/include/elf/internal.h | 279 + contrib/binutils-2.17/include/elf/ip2k.h | 62 + contrib/binutils-2.17/include/elf/iq2000.h | 58 + contrib/binutils-2.17/include/elf/m32c.h | 67 + contrib/binutils-2.17/include/elf/m32r.h | 122 + contrib/binutils-2.17/include/elf/m68hc11.h | 95 + contrib/binutils-2.17/include/elf/m68k.h | 75 + contrib/binutils-2.17/include/elf/mcore.h | 46 + contrib/binutils-2.17/include/elf/mips.h | 1008 ++ contrib/binutils-2.17/include/elf/mmix.h | 171 + contrib/binutils-2.17/include/elf/mn10200.h | 39 + contrib/binutils-2.17/include/elf/mn10300.h | 68 + contrib/binutils-2.17/include/elf/msp430.h | 58 + contrib/binutils-2.17/include/elf/mt.h | 46 + contrib/binutils-2.17/include/elf/or32.h | 62 + contrib/binutils-2.17/include/elf/pj.h | 44 + contrib/binutils-2.17/include/elf/ppc.h | 174 + contrib/binutils-2.17/include/elf/ppc64.h | 156 + contrib/binutils-2.17/include/elf/reloc-macros.h | 101 + contrib/binutils-2.17/include/elf/s390.h | 125 + contrib/binutils-2.17/include/elf/sh.h | 233 + contrib/binutils-2.17/include/elf/sparc.h | 176 + contrib/binutils-2.17/include/elf/v850.h | 123 + contrib/binutils-2.17/include/elf/vax.h | 51 + contrib/binutils-2.17/include/elf/x86-64.h | 87 + contrib/binutils-2.17/include/elf/xstormy16.h | 57 + contrib/binutils-2.17/include/elf/xtensa.h | 198 + contrib/binutils-2.17/include/filenames.h | 51 + contrib/binutils-2.17/include/floatformat.h | 140 + contrib/binutils-2.17/include/fnmatch.h | 70 + contrib/binutils-2.17/include/fopen-same.h | 27 + contrib/binutils-2.17/include/getopt.h | 144 + contrib/binutils-2.17/include/hashtab.h | 206 + contrib/binutils-2.17/include/ieee.h | 165 + contrib/binutils-2.17/include/libiberty.h | 631 ++ contrib/binutils-2.17/include/objalloc.h | 115 + contrib/binutils-2.17/include/obstack.h | 545 ++ contrib/binutils-2.17/include/opcode/i386.h | 1715 ++++ contrib/binutils-2.17/include/progress.h | 37 + contrib/binutils-2.17/include/safe-ctype.h | 119 + contrib/binutils-2.17/include/symcat.h | 49 + contrib/binutils-2.17/ld/README | 67 + contrib/binutils-2.17/ld/config.in | 222 + contrib/binutils-2.17/ld/configdoc.texi | 22 + contrib/binutils-2.17/ld/elf-hints-local.h | 44 + contrib/binutils-2.17/ld/emulparams/README | 2 + contrib/binutils-2.17/ld/emulparams/elf_i386.sh | 14 + contrib/binutils-2.17/ld/emulparams/elf_x86_64.sh | 33 + contrib/binutils-2.17/ld/emultempl/README | 3 + contrib/binutils-2.17/ld/emultempl/astring.sed | 13 + contrib/binutils-2.17/ld/emultempl/elf32.em | 1971 ++++ contrib/binutils-2.17/ld/fdl.texi | 367 + contrib/binutils-2.17/ld/gen-doc.texi | 22 + contrib/binutils-2.17/ld/genscripts.sh | 371 + contrib/binutils-2.17/ld/ld.1 | 2071 ++++ contrib/binutils-2.17/ld/ld.h | 297 + contrib/binutils-2.17/ld/ld.texinfo | 6654 +++++++++++++ contrib/binutils-2.17/ld/ldcref.c | 598 ++ contrib/binutils-2.17/ld/ldctor.c | 376 + contrib/binutils-2.17/ld/ldctor.h | 60 + contrib/binutils-2.17/ld/ldemul.c | 323 + contrib/binutils-2.17/ld/ldemul.h | 204 + contrib/binutils-2.17/ld/ldexp.c | 1095 +++ contrib/binutils-2.17/ld/ldexp.h | 183 + contrib/binutils-2.17/ld/ldfile.c | 547 ++ contrib/binutils-2.17/ld/ldfile.h | 63 + contrib/binutils-2.17/ld/ldgram.c | 4163 ++++++++ contrib/binutils-2.17/ld/ldgram.h | 307 + contrib/binutils-2.17/ld/ldint.texinfo | 1058 +++ contrib/binutils-2.17/ld/ldlang.c | 6764 +++++++++++++ contrib/binutils-2.17/ld/ldlang.h | 608 ++ contrib/binutils-2.17/ld/ldlex.c | 3833 ++++++++ contrib/binutils-2.17/ld/ldlex.h | 63 + contrib/binutils-2.17/ld/ldmain.c | 1528 +++ contrib/binutils-2.17/ld/ldmain.h | 47 + contrib/binutils-2.17/ld/ldmisc.c | 560 ++ contrib/binutils-2.17/ld/ldmisc.h | 45 + contrib/binutils-2.17/ld/ldver.c | 59 + contrib/binutils-2.17/ld/ldver.h | 21 + contrib/binutils-2.17/ld/ldver.texi | 1 + contrib/binutils-2.17/ld/ldwrite.c | 568 ++ contrib/binutils-2.17/ld/ldwrite.h | 21 + contrib/binutils-2.17/ld/lexsup.c | 1553 +++ contrib/binutils-2.17/ld/mri.c | 316 + contrib/binutils-2.17/ld/mri.h | 37 + contrib/binutils-2.17/ld/scripttempl/README | 4 + contrib/binutils-2.17/ld/scripttempl/elf.sc | 507 + contrib/binutils-2.17/ld/sysdep.h | 96 + contrib/binutils-2.17/libiberty/COPYING.LIB | 504 + contrib/binutils-2.17/libiberty/README | 66 + contrib/binutils-2.17/libiberty/argv.c | 460 + contrib/binutils-2.17/libiberty/at-file.texi | 15 + contrib/binutils-2.17/libiberty/choose-temp.c | 72 + contrib/binutils-2.17/libiberty/concat.c | 232 + contrib/binutils-2.17/libiberty/config.in | 444 + contrib/binutils-2.17/libiberty/cp-demangle.c | 4351 +++++++++ contrib/binutils-2.17/libiberty/cp-demangle.h | 161 + contrib/binutils-2.17/libiberty/cp-demint.c | 234 + contrib/binutils-2.17/libiberty/cplus-dem.c | 4717 ++++++++++ contrib/binutils-2.17/libiberty/dyn-string.c | 397 + contrib/binutils-2.17/libiberty/floatformat.c | 642 ++ contrib/binutils-2.17/libiberty/getopt.c | 1052 +++ contrib/binutils-2.17/libiberty/getopt1.c | 180 + contrib/binutils-2.17/libiberty/getpwd.c | 128 + contrib/binutils-2.17/libiberty/getruntime.c | 116 + contrib/binutils-2.17/libiberty/hashtab.c | 934 ++ contrib/binutils-2.17/libiberty/hex.c | 192 + contrib/binutils-2.17/libiberty/lbasename.c | 64 + contrib/binutils-2.17/libiberty/lrealpath.c | 157 + .../binutils-2.17/libiberty/make-relative-prefix.c | 389 + contrib/binutils-2.17/libiberty/make-temp-file.c | 177 + contrib/binutils-2.17/libiberty/objalloc.c | 291 + contrib/binutils-2.17/libiberty/obstack.c | 510 + contrib/binutils-2.17/libiberty/safe-ctype.c | 255 + contrib/binutils-2.17/libiberty/stpcpy.c | 43 + .../binutils-2.17/libiberty/unlink-if-ordinary.c | 72 + contrib/binutils-2.17/libiberty/xatexit.c | 99 + contrib/binutils-2.17/libiberty/xexit.c | 52 + contrib/binutils-2.17/libiberty/xmalloc.c | 184 + contrib/binutils-2.17/libiberty/xstrdup.c | 36 + contrib/binutils-2.17/libiberty/xstrerror.c | 79 + contrib/binutils-2.17/opcodes/config.in | 166 + contrib/binutils-2.17/opcodes/dis-buf.c | 102 + contrib/binutils-2.17/opcodes/dis-init.c | 43 + contrib/binutils-2.17/opcodes/disassemble.c | 480 + contrib/binutils-2.17/opcodes/i386-dis.c | 4861 ++++++++++ contrib/binutils-2.17/opcodes/opintl.h | 42 + contrib/binutils-2.17/opcodes/sysdep.h | 43 + 415 files changed, 305992 insertions(+) create mode 100644 contrib/binutils-2.17/COPYING create mode 100644 contrib/binutils-2.17/COPYING.LIB create mode 100644 contrib/binutils-2.17/README create mode 100644 contrib/binutils-2.17/bfd/COPYING create mode 100644 contrib/binutils-2.17/bfd/PORTING create mode 100644 contrib/binutils-2.17/bfd/README create mode 100644 contrib/binutils-2.17/bfd/archive.c create mode 100644 contrib/binutils-2.17/bfd/archive64.c create mode 100644 contrib/binutils-2.17/bfd/archures.c create mode 100644 contrib/binutils-2.17/bfd/bfd-in.h create mode 100644 contrib/binutils-2.17/bfd/bfd-in2.h create mode 100644 contrib/binutils-2.17/bfd/bfd.c create mode 100644 contrib/binutils-2.17/bfd/bfdio.c create mode 100644 contrib/binutils-2.17/bfd/binary.c create mode 100644 contrib/binutils-2.17/bfd/cache.c create mode 100644 contrib/binutils-2.17/bfd/coffgen.c create mode 100644 contrib/binutils-2.17/bfd/config.bfd create mode 100644 contrib/binutils-2.17/bfd/config.in create mode 100644 contrib/binutils-2.17/bfd/corefile.c create mode 100644 contrib/binutils-2.17/bfd/cpu-i386.c create mode 100644 contrib/binutils-2.17/bfd/doc/aoutx.texi create mode 100644 contrib/binutils-2.17/bfd/doc/archive.texi create mode 100644 contrib/binutils-2.17/bfd/doc/archures.texi create mode 100644 contrib/binutils-2.17/bfd/doc/bfd.texinfo create mode 100644 contrib/binutils-2.17/bfd/doc/bfdint.texi create mode 100644 contrib/binutils-2.17/bfd/doc/bfdio.texi create mode 100644 contrib/binutils-2.17/bfd/doc/bfdsumm.texi create mode 100644 contrib/binutils-2.17/bfd/doc/bfdt.texi create mode 100644 contrib/binutils-2.17/bfd/doc/bfdwin.texi create mode 100644 contrib/binutils-2.17/bfd/doc/cache.texi create mode 100644 contrib/binutils-2.17/bfd/doc/coffcode.texi create mode 100644 contrib/binutils-2.17/bfd/doc/core.texi create mode 100644 contrib/binutils-2.17/bfd/doc/elf.texi create mode 100644 contrib/binutils-2.17/bfd/doc/elfcode.texi create mode 100644 contrib/binutils-2.17/bfd/doc/format.texi create mode 100644 contrib/binutils-2.17/bfd/doc/hash.texi create mode 100644 contrib/binutils-2.17/bfd/doc/init.texi create mode 100644 contrib/binutils-2.17/bfd/doc/libbfd.texi create mode 100644 contrib/binutils-2.17/bfd/doc/linker.texi create mode 100644 contrib/binutils-2.17/bfd/doc/mmo.texi create mode 100644 contrib/binutils-2.17/bfd/doc/opncls.texi create mode 100644 contrib/binutils-2.17/bfd/doc/reloc.texi create mode 100644 contrib/binutils-2.17/bfd/doc/section.texi create mode 100644 contrib/binutils-2.17/bfd/doc/syms.texi create mode 100644 contrib/binutils-2.17/bfd/doc/targets.texi create mode 100644 contrib/binutils-2.17/bfd/dwarf1.c create mode 100644 contrib/binutils-2.17/bfd/dwarf2.c create mode 100644 contrib/binutils-2.17/bfd/efi-app-ia32.c create mode 100644 contrib/binutils-2.17/bfd/efi-app-ia64.c create mode 100644 contrib/binutils-2.17/bfd/elf-bfd.h create mode 100644 contrib/binutils-2.17/bfd/elf-eh-frame.c create mode 100644 contrib/binutils-2.17/bfd/elf-strtab.c create mode 100644 contrib/binutils-2.17/bfd/elf-vxworks.c create mode 100644 contrib/binutils-2.17/bfd/elf-vxworks.h create mode 100644 contrib/binutils-2.17/bfd/elf.c create mode 100644 contrib/binutils-2.17/bfd/elf32-i386.c create mode 100644 contrib/binutils-2.17/bfd/elf32.c create mode 100644 contrib/binutils-2.17/bfd/elf64-gen.c create mode 100644 contrib/binutils-2.17/bfd/elf64-x86-64.c create mode 100644 contrib/binutils-2.17/bfd/elf64.c create mode 100644 contrib/binutils-2.17/bfd/elfcode.h create mode 100644 contrib/binutils-2.17/bfd/elfcore.h create mode 100644 contrib/binutils-2.17/bfd/elflink.c create mode 100644 contrib/binutils-2.17/bfd/elfxx-target.h create mode 100644 contrib/binutils-2.17/bfd/format.c create mode 100644 contrib/binutils-2.17/bfd/genlink.h create mode 100644 contrib/binutils-2.17/bfd/hash.c create mode 100644 contrib/binutils-2.17/bfd/ihex.c create mode 100644 contrib/binutils-2.17/bfd/init.c create mode 100644 contrib/binutils-2.17/bfd/libaout.h create mode 100644 contrib/binutils-2.17/bfd/libbfd-in.h create mode 100644 contrib/binutils-2.17/bfd/libbfd.c create mode 100644 contrib/binutils-2.17/bfd/libbfd.h create mode 100644 contrib/binutils-2.17/bfd/libcoff.h create mode 100644 contrib/binutils-2.17/bfd/libecoff.h create mode 100644 contrib/binutils-2.17/bfd/linker.c create mode 100644 contrib/binutils-2.17/bfd/merge.c create mode 100644 contrib/binutils-2.17/bfd/opncls.c create mode 100644 contrib/binutils-2.17/bfd/reloc.c create mode 100644 contrib/binutils-2.17/bfd/section.c create mode 100644 contrib/binutils-2.17/bfd/simple.c create mode 100644 contrib/binutils-2.17/bfd/srec.c create mode 100644 contrib/binutils-2.17/bfd/stab-syms.c create mode 100644 contrib/binutils-2.17/bfd/stabs.c create mode 100644 contrib/binutils-2.17/bfd/syms.c create mode 100644 contrib/binutils-2.17/bfd/sysdep.h create mode 100644 contrib/binutils-2.17/bfd/targets.c create mode 100644 contrib/binutils-2.17/bfd/targmatch.sed create mode 100644 contrib/binutils-2.17/bfd/tekhex.c create mode 100644 contrib/binutils-2.17/bfd/version.h create mode 100644 contrib/binutils-2.17/binutils/addr2line.c create mode 100644 contrib/binutils-2.17/binutils/ar.c create mode 100644 contrib/binutils-2.17/binutils/arlex.c create mode 100644 contrib/binutils-2.17/binutils/arparse.c create mode 100644 contrib/binutils-2.17/binutils/arparse.h create mode 100644 contrib/binutils-2.17/binutils/arsup.c create mode 100644 contrib/binutils-2.17/binutils/arsup.h create mode 100644 contrib/binutils-2.17/binutils/binemul.c create mode 100644 contrib/binutils-2.17/binutils/binemul.h create mode 100644 contrib/binutils-2.17/binutils/bucomm.c create mode 100644 contrib/binutils-2.17/binutils/bucomm.h create mode 100644 contrib/binutils-2.17/binutils/budbg.h create mode 100644 contrib/binutils-2.17/binutils/budemang.c create mode 100644 contrib/binutils-2.17/binutils/budemang.h create mode 100644 contrib/binutils-2.17/binutils/config.in create mode 100644 contrib/binutils-2.17/binutils/debug.c create mode 100644 contrib/binutils-2.17/binutils/debug.h create mode 100644 contrib/binutils-2.17/binutils/doc/addr2line.1 create mode 100644 contrib/binutils-2.17/binutils/doc/ar.1 create mode 100644 contrib/binutils-2.17/binutils/doc/binutils.texi create mode 100644 contrib/binutils-2.17/binutils/doc/config.texi create mode 100644 contrib/binutils-2.17/binutils/doc/fdl.texi create mode 100644 contrib/binutils-2.17/binutils/doc/nm.1 create mode 100644 contrib/binutils-2.17/binutils/doc/objcopy.1 create mode 100644 contrib/binutils-2.17/binutils/doc/objdump.1 create mode 100644 contrib/binutils-2.17/binutils/doc/ranlib.1 create mode 100644 contrib/binutils-2.17/binutils/doc/readelf.1 create mode 100644 contrib/binutils-2.17/binutils/doc/size.1 create mode 100644 contrib/binutils-2.17/binutils/doc/strings.1 create mode 100644 contrib/binutils-2.17/binutils/doc/strip.1 create mode 100644 contrib/binutils-2.17/binutils/dwarf.c create mode 100644 contrib/binutils-2.17/binutils/dwarf.h create mode 100644 contrib/binutils-2.17/binutils/emul_vanilla.c create mode 100644 contrib/binutils-2.17/binutils/filemode.c create mode 100644 contrib/binutils-2.17/binutils/ieee.c create mode 100644 contrib/binutils-2.17/binutils/is-ranlib.c create mode 100644 contrib/binutils-2.17/binutils/is-strip.c create mode 100644 contrib/binutils-2.17/binutils/nm.c create mode 100644 contrib/binutils-2.17/binutils/not-ranlib.c create mode 100644 contrib/binutils-2.17/binutils/not-strip.c create mode 100644 contrib/binutils-2.17/binutils/objcopy.c create mode 100644 contrib/binutils-2.17/binutils/objdump.c create mode 100644 contrib/binutils-2.17/binutils/prdbg.c create mode 100644 contrib/binutils-2.17/binutils/rdcoff.c create mode 100644 contrib/binutils-2.17/binutils/rddbg.c create mode 100644 contrib/binutils-2.17/binutils/readelf.c create mode 100644 contrib/binutils-2.17/binutils/rename.c create mode 100644 contrib/binutils-2.17/binutils/size.c create mode 100644 contrib/binutils-2.17/binutils/stabs.c create mode 100644 contrib/binutils-2.17/binutils/strings.c create mode 100644 contrib/binutils-2.17/binutils/unwind-ia64.c create mode 100644 contrib/binutils-2.17/binutils/unwind-ia64.h create mode 100644 contrib/binutils-2.17/binutils/version.c create mode 100644 contrib/binutils-2.17/binutils/wrstabs.c create mode 100644 contrib/binutils-2.17/gas/CONTRIBUTORS create mode 100644 contrib/binutils-2.17/gas/COPYING create mode 100644 contrib/binutils-2.17/gas/README create mode 100644 contrib/binutils-2.17/gas/app.c create mode 100644 contrib/binutils-2.17/gas/as.c create mode 100644 contrib/binutils-2.17/gas/as.h create mode 100644 contrib/binutils-2.17/gas/asintl.h create mode 100644 contrib/binutils-2.17/gas/atof-generic.c create mode 100644 contrib/binutils-2.17/gas/bignum.h create mode 100644 contrib/binutils-2.17/gas/bit_fix.h create mode 100644 contrib/binutils-2.17/gas/cond.c create mode 100644 contrib/binutils-2.17/gas/config.in create mode 100644 contrib/binutils-2.17/gas/config/atof-ieee.c create mode 100644 contrib/binutils-2.17/gas/config/obj-elf.c create mode 100644 contrib/binutils-2.17/gas/config/obj-elf.h create mode 100644 contrib/binutils-2.17/gas/config/tc-i386.c create mode 100644 contrib/binutils-2.17/gas/config/tc-i386.h create mode 100644 contrib/binutils-2.17/gas/depend.c create mode 100644 contrib/binutils-2.17/gas/doc/as.1 create mode 100644 contrib/binutils-2.17/gas/doc/as.texinfo create mode 100644 contrib/binutils-2.17/gas/doc/asconfig.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-alpha.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-arc.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-arm.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-bfin.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-cris.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-d10v.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-d30v.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-h8300.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-hppa.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-i370.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-i386.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-i860.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-i960.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-ia64.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-ip2k.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-m32c.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-m32r.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-m68hc11.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-m68k.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-mips.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-mmix.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-msp430.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-pdp11.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-pj.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-ppc.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-sh.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-sh64.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-sparc.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-tic54x.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-v850.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-vax.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-xtensa.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-z80.texi create mode 100644 contrib/binutils-2.17/gas/doc/c-z8k.texi create mode 100644 contrib/binutils-2.17/gas/doc/fdl.texi create mode 100644 contrib/binutils-2.17/gas/doc/gasver.texi create mode 100644 contrib/binutils-2.17/gas/dw2gencfi.c create mode 100644 contrib/binutils-2.17/gas/dw2gencfi.h create mode 100644 contrib/binutils-2.17/gas/dwarf2dbg.c create mode 100644 contrib/binutils-2.17/gas/dwarf2dbg.h create mode 100644 contrib/binutils-2.17/gas/ecoff.c create mode 100644 contrib/binutils-2.17/gas/ecoff.h create mode 100644 contrib/binutils-2.17/gas/ehopt.c create mode 100644 contrib/binutils-2.17/gas/expr.c create mode 100644 contrib/binutils-2.17/gas/expr.h create mode 100644 contrib/binutils-2.17/gas/flonum-copy.c create mode 100644 contrib/binutils-2.17/gas/flonum-konst.c create mode 100644 contrib/binutils-2.17/gas/flonum-mult.c create mode 100644 contrib/binutils-2.17/gas/flonum.h create mode 100644 contrib/binutils-2.17/gas/frags.c create mode 100644 contrib/binutils-2.17/gas/frags.h create mode 100644 contrib/binutils-2.17/gas/hash.c create mode 100644 contrib/binutils-2.17/gas/hash.h create mode 100644 contrib/binutils-2.17/gas/input-file.c create mode 100644 contrib/binutils-2.17/gas/input-file.h create mode 100644 contrib/binutils-2.17/gas/input-scrub.c create mode 100644 contrib/binutils-2.17/gas/itbl-lex.c create mode 100644 contrib/binutils-2.17/gas/itbl-lex.h create mode 100644 contrib/binutils-2.17/gas/itbl-ops.c create mode 100644 contrib/binutils-2.17/gas/itbl-ops.h create mode 100644 contrib/binutils-2.17/gas/itbl-parse.c create mode 100644 contrib/binutils-2.17/gas/itbl-parse.h create mode 100644 contrib/binutils-2.17/gas/listing.c create mode 100644 contrib/binutils-2.17/gas/listing.h create mode 100644 contrib/binutils-2.17/gas/literal.c create mode 100644 contrib/binutils-2.17/gas/macro.c create mode 100644 contrib/binutils-2.17/gas/macro.h create mode 100644 contrib/binutils-2.17/gas/messages.c create mode 100644 contrib/binutils-2.17/gas/obj.h create mode 100644 contrib/binutils-2.17/gas/output-file.c create mode 100644 contrib/binutils-2.17/gas/output-file.h create mode 100644 contrib/binutils-2.17/gas/read.c create mode 100644 contrib/binutils-2.17/gas/read.h create mode 100644 contrib/binutils-2.17/gas/sb.c create mode 100644 contrib/binutils-2.17/gas/sb.h create mode 100644 contrib/binutils-2.17/gas/stabs.c create mode 100644 contrib/binutils-2.17/gas/struc-symbol.h create mode 100644 contrib/binutils-2.17/gas/subsegs.c create mode 100644 contrib/binutils-2.17/gas/subsegs.h create mode 100644 contrib/binutils-2.17/gas/symbols.c create mode 100644 contrib/binutils-2.17/gas/symbols.h create mode 100644 contrib/binutils-2.17/gas/tc.h create mode 100644 contrib/binutils-2.17/gas/write.c create mode 100644 contrib/binutils-2.17/gas/write.h create mode 100644 contrib/binutils-2.17/include/COPYING create mode 100644 contrib/binutils-2.17/include/ansidecl.h create mode 100644 contrib/binutils-2.17/include/aout/aout64.h create mode 100644 contrib/binutils-2.17/include/aout/ar.h create mode 100644 contrib/binutils-2.17/include/aout/ranlib.h create mode 100644 contrib/binutils-2.17/include/aout/stab.def create mode 100644 contrib/binutils-2.17/include/aout/stab_gnu.h create mode 100644 contrib/binutils-2.17/include/bfdlink.h create mode 100644 contrib/binutils-2.17/include/bin-bugs.h create mode 100644 contrib/binutils-2.17/include/coff/ecoff.h create mode 100644 contrib/binutils-2.17/include/coff/internal.h create mode 100644 contrib/binutils-2.17/include/coff/sym.h create mode 100644 contrib/binutils-2.17/include/demangle.h create mode 100644 contrib/binutils-2.17/include/dis-asm.h create mode 100644 contrib/binutils-2.17/include/dyn-string.h create mode 100644 contrib/binutils-2.17/include/elf/alpha.h create mode 100644 contrib/binutils-2.17/include/elf/arc.h create mode 100644 contrib/binutils-2.17/include/elf/arm.h create mode 100644 contrib/binutils-2.17/include/elf/avr.h create mode 100644 contrib/binutils-2.17/include/elf/bfin.h create mode 100644 contrib/binutils-2.17/include/elf/common.h create mode 100644 contrib/binutils-2.17/include/elf/cris.h create mode 100644 contrib/binutils-2.17/include/elf/crx.h create mode 100644 contrib/binutils-2.17/include/elf/d10v.h create mode 100644 contrib/binutils-2.17/include/elf/d30v.h create mode 100644 contrib/binutils-2.17/include/elf/dlx.h create mode 100644 contrib/binutils-2.17/include/elf/dwarf.h create mode 100644 contrib/binutils-2.17/include/elf/dwarf2.h create mode 100644 contrib/binutils-2.17/include/elf/external.h create mode 100644 contrib/binutils-2.17/include/elf/fr30.h create mode 100644 contrib/binutils-2.17/include/elf/frv.h create mode 100644 contrib/binutils-2.17/include/elf/h8.h create mode 100644 contrib/binutils-2.17/include/elf/hppa.h create mode 100644 contrib/binutils-2.17/include/elf/i370.h create mode 100644 contrib/binutils-2.17/include/elf/i386.h create mode 100644 contrib/binutils-2.17/include/elf/i860.h create mode 100644 contrib/binutils-2.17/include/elf/i960.h create mode 100644 contrib/binutils-2.17/include/elf/ia64.h create mode 100644 contrib/binutils-2.17/include/elf/internal.h create mode 100644 contrib/binutils-2.17/include/elf/ip2k.h create mode 100644 contrib/binutils-2.17/include/elf/iq2000.h create mode 100644 contrib/binutils-2.17/include/elf/m32c.h create mode 100644 contrib/binutils-2.17/include/elf/m32r.h create mode 100644 contrib/binutils-2.17/include/elf/m68hc11.h create mode 100644 contrib/binutils-2.17/include/elf/m68k.h create mode 100644 contrib/binutils-2.17/include/elf/mcore.h create mode 100644 contrib/binutils-2.17/include/elf/mips.h create mode 100644 contrib/binutils-2.17/include/elf/mmix.h create mode 100644 contrib/binutils-2.17/include/elf/mn10200.h create mode 100644 contrib/binutils-2.17/include/elf/mn10300.h create mode 100644 contrib/binutils-2.17/include/elf/msp430.h create mode 100644 contrib/binutils-2.17/include/elf/mt.h create mode 100644 contrib/binutils-2.17/include/elf/or32.h create mode 100644 contrib/binutils-2.17/include/elf/pj.h create mode 100644 contrib/binutils-2.17/include/elf/ppc.h create mode 100644 contrib/binutils-2.17/include/elf/ppc64.h create mode 100644 contrib/binutils-2.17/include/elf/reloc-macros.h create mode 100644 contrib/binutils-2.17/include/elf/s390.h create mode 100644 contrib/binutils-2.17/include/elf/sh.h create mode 100644 contrib/binutils-2.17/include/elf/sparc.h create mode 100644 contrib/binutils-2.17/include/elf/v850.h create mode 100644 contrib/binutils-2.17/include/elf/vax.h create mode 100644 contrib/binutils-2.17/include/elf/x86-64.h create mode 100644 contrib/binutils-2.17/include/elf/xstormy16.h create mode 100644 contrib/binutils-2.17/include/elf/xtensa.h create mode 100644 contrib/binutils-2.17/include/filenames.h create mode 100644 contrib/binutils-2.17/include/floatformat.h create mode 100644 contrib/binutils-2.17/include/fnmatch.h create mode 100644 contrib/binutils-2.17/include/fopen-same.h create mode 100644 contrib/binutils-2.17/include/getopt.h create mode 100644 contrib/binutils-2.17/include/hashtab.h create mode 100644 contrib/binutils-2.17/include/ieee.h create mode 100644 contrib/binutils-2.17/include/libiberty.h create mode 100644 contrib/binutils-2.17/include/objalloc.h create mode 100644 contrib/binutils-2.17/include/obstack.h create mode 100644 contrib/binutils-2.17/include/opcode/i386.h create mode 100644 contrib/binutils-2.17/include/progress.h create mode 100644 contrib/binutils-2.17/include/safe-ctype.h create mode 100644 contrib/binutils-2.17/include/symcat.h create mode 100644 contrib/binutils-2.17/ld/README create mode 100644 contrib/binutils-2.17/ld/config.in create mode 100644 contrib/binutils-2.17/ld/configdoc.texi create mode 100644 contrib/binutils-2.17/ld/elf-hints-local.h create mode 100644 contrib/binutils-2.17/ld/emulparams/README create mode 100644 contrib/binutils-2.17/ld/emulparams/elf_i386.sh create mode 100644 contrib/binutils-2.17/ld/emulparams/elf_x86_64.sh create mode 100644 contrib/binutils-2.17/ld/emultempl/README create mode 100644 contrib/binutils-2.17/ld/emultempl/astring.sed create mode 100644 contrib/binutils-2.17/ld/emultempl/elf32.em create mode 100644 contrib/binutils-2.17/ld/fdl.texi create mode 100644 contrib/binutils-2.17/ld/gen-doc.texi create mode 100644 contrib/binutils-2.17/ld/genscripts.sh create mode 100644 contrib/binutils-2.17/ld/ld.1 create mode 100644 contrib/binutils-2.17/ld/ld.h create mode 100644 contrib/binutils-2.17/ld/ld.texinfo create mode 100644 contrib/binutils-2.17/ld/ldcref.c create mode 100644 contrib/binutils-2.17/ld/ldctor.c create mode 100644 contrib/binutils-2.17/ld/ldctor.h create mode 100644 contrib/binutils-2.17/ld/ldemul.c create mode 100644 contrib/binutils-2.17/ld/ldemul.h create mode 100644 contrib/binutils-2.17/ld/ldexp.c create mode 100644 contrib/binutils-2.17/ld/ldexp.h create mode 100644 contrib/binutils-2.17/ld/ldfile.c create mode 100644 contrib/binutils-2.17/ld/ldfile.h create mode 100644 contrib/binutils-2.17/ld/ldgram.c create mode 100644 contrib/binutils-2.17/ld/ldgram.h create mode 100644 contrib/binutils-2.17/ld/ldint.texinfo create mode 100644 contrib/binutils-2.17/ld/ldlang.c create mode 100644 contrib/binutils-2.17/ld/ldlang.h create mode 100644 contrib/binutils-2.17/ld/ldlex.c create mode 100644 contrib/binutils-2.17/ld/ldlex.h create mode 100644 contrib/binutils-2.17/ld/ldmain.c create mode 100644 contrib/binutils-2.17/ld/ldmain.h create mode 100644 contrib/binutils-2.17/ld/ldmisc.c create mode 100644 contrib/binutils-2.17/ld/ldmisc.h create mode 100644 contrib/binutils-2.17/ld/ldver.c create mode 100644 contrib/binutils-2.17/ld/ldver.h create mode 100644 contrib/binutils-2.17/ld/ldver.texi create mode 100644 contrib/binutils-2.17/ld/ldwrite.c create mode 100644 contrib/binutils-2.17/ld/ldwrite.h create mode 100644 contrib/binutils-2.17/ld/lexsup.c create mode 100644 contrib/binutils-2.17/ld/mri.c create mode 100644 contrib/binutils-2.17/ld/mri.h create mode 100644 contrib/binutils-2.17/ld/scripttempl/README create mode 100644 contrib/binutils-2.17/ld/scripttempl/elf.sc create mode 100644 contrib/binutils-2.17/ld/sysdep.h create mode 100644 contrib/binutils-2.17/libiberty/COPYING.LIB create mode 100644 contrib/binutils-2.17/libiberty/README create mode 100644 contrib/binutils-2.17/libiberty/argv.c create mode 100644 contrib/binutils-2.17/libiberty/at-file.texi create mode 100644 contrib/binutils-2.17/libiberty/choose-temp.c create mode 100644 contrib/binutils-2.17/libiberty/concat.c create mode 100644 contrib/binutils-2.17/libiberty/config.in create mode 100644 contrib/binutils-2.17/libiberty/cp-demangle.c create mode 100644 contrib/binutils-2.17/libiberty/cp-demangle.h create mode 100644 contrib/binutils-2.17/libiberty/cp-demint.c create mode 100644 contrib/binutils-2.17/libiberty/cplus-dem.c create mode 100644 contrib/binutils-2.17/libiberty/dyn-string.c create mode 100644 contrib/binutils-2.17/libiberty/floatformat.c create mode 100644 contrib/binutils-2.17/libiberty/getopt.c create mode 100644 contrib/binutils-2.17/libiberty/getopt1.c create mode 100644 contrib/binutils-2.17/libiberty/getpwd.c create mode 100644 contrib/binutils-2.17/libiberty/getruntime.c create mode 100644 contrib/binutils-2.17/libiberty/hashtab.c create mode 100644 contrib/binutils-2.17/libiberty/hex.c create mode 100644 contrib/binutils-2.17/libiberty/lbasename.c create mode 100644 contrib/binutils-2.17/libiberty/lrealpath.c create mode 100644 contrib/binutils-2.17/libiberty/make-relative-prefix.c create mode 100644 contrib/binutils-2.17/libiberty/make-temp-file.c create mode 100644 contrib/binutils-2.17/libiberty/objalloc.c create mode 100644 contrib/binutils-2.17/libiberty/obstack.c create mode 100644 contrib/binutils-2.17/libiberty/safe-ctype.c create mode 100644 contrib/binutils-2.17/libiberty/stpcpy.c create mode 100644 contrib/binutils-2.17/libiberty/unlink-if-ordinary.c create mode 100644 contrib/binutils-2.17/libiberty/xatexit.c create mode 100644 contrib/binutils-2.17/libiberty/xexit.c create mode 100644 contrib/binutils-2.17/libiberty/xmalloc.c create mode 100644 contrib/binutils-2.17/libiberty/xstrdup.c create mode 100644 contrib/binutils-2.17/libiberty/xstrerror.c create mode 100644 contrib/binutils-2.17/opcodes/config.in create mode 100644 contrib/binutils-2.17/opcodes/dis-buf.c create mode 100644 contrib/binutils-2.17/opcodes/dis-init.c create mode 100644 contrib/binutils-2.17/opcodes/disassemble.c create mode 100644 contrib/binutils-2.17/opcodes/i386-dis.c create mode 100644 contrib/binutils-2.17/opcodes/opintl.h create mode 100644 contrib/binutils-2.17/opcodes/sysdep.h diff --git a/contrib/binutils-2.17/COPYING b/contrib/binutils-2.17/COPYING new file mode 100644 index 0000000000..623b6258a1 --- /dev/null +++ b/contrib/binutils-2.17/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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.17/COPYING.LIB b/contrib/binutils-2.17/COPYING.LIB new file mode 100644 index 0000000000..778d0bb5b2 --- /dev/null +++ b/contrib/binutils-2.17/COPYING.LIB @@ -0,0 +1,482 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, 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.17/README b/contrib/binutils-2.17/README new file mode 100644 index 0000000000..eb0e436d86 --- /dev/null +++ b/contrib/binutils-2.17/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.17/bfd/COPYING b/contrib/binutils-2.17/bfd/COPYING new file mode 100644 index 0000000000..22c7fc2011 --- /dev/null +++ b/contrib/binutils-2.17/bfd/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright 1989, 1991, 1997 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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.17/bfd/PORTING b/contrib/binutils-2.17/bfd/PORTING new file mode 100644 index 0000000000..c8bfd77b96 --- /dev/null +++ b/contrib/binutils-2.17/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.17/bfd/README b/contrib/binutils-2.17/bfd/README new file mode 100644 index 0000000000..fe6b6f33c1 --- /dev/null +++ b/contrib/binutils-2.17/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.17/bfd/archive.c b/contrib/binutils-2.17/bfd/archive.c new file mode 100644 index 0000000000..5a12f01f7c --- /dev/null +++ b/contrib/binutils-2.17/bfd/archive.c @@ -0,0 +1,2157 @@ +/* BFD back-end for archive files (libraries). + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004, 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 <>. + +SUBSECTION + Archive functions +*/ + +/* 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 spaces) 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 "libiberty.h" +#include "libbfd.h" +#include "aout/ar.h" +#include "aout/ranlib.h" +#include "safe-ctype.h" +#include "hashtab.h" + +#ifndef errno +extern int errno; +#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 *arbfd; +}; + +#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) + +void +_bfd_ar_spacepad (char *p, size_t n, const char *fmt, long val) +{ + static char buf[20]; + size_t len; + snprintf (buf, sizeof (buf), fmt, val); + len = strlen (buf); + if (len < n) + { + memcpy (p, buf, len); + memset (p + len, ' ', n - len); + } + else + memcpy (p, buf, n); +} + +bfd_boolean +_bfd_generic_mkarchive (bfd *abfd) +{ + bfd_size_type amt = sizeof (struct artdata); + + abfd->tdata.aout_ar_data = bfd_zalloc (abfd, amt); + if (bfd_ardata (abfd) == NULL) + return FALSE; + + /* Already cleared by bfd_zalloc above. + 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)->extended_names_size = 0; + 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 (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 (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 (bfd *output_archive, bfd *new_head) +{ + output_archive->archive_head = new_head; + return TRUE; +} + +bfd * +_bfd_look_for_bfd_in_cache (bfd *arch_bfd, file_ptr filepos) +{ + htab_t hash_table = bfd_ardata (arch_bfd)->cache; + struct ar_cache m; + m.ptr = filepos; + + if (hash_table) + { + struct ar_cache *entry = (struct ar_cache *) htab_find (hash_table, &m); + if (!entry) + return NULL; + else + return entry->arbfd; + } + else + return NULL; +} + +static hashval_t +hash_file_ptr (const PTR p) +{ + return (hashval_t) (((struct ar_cache *) p)->ptr); +} + +/* Returns non-zero if P1 and P2 are equal. */ + +static int +eq_file_ptr (const PTR p1, const PTR p2) +{ + struct ar_cache *arc1 = (struct ar_cache *) p1; + struct ar_cache *arc2 = (struct ar_cache *) p2; + return arc1->ptr == arc2->ptr; +} + +/* Kind of stupid to call cons for each one, but we don't do too many. */ + +bfd_boolean +_bfd_add_bfd_to_archive_cache (bfd *arch_bfd, file_ptr filepos, bfd *new_elt) +{ + struct ar_cache *cache; + htab_t hash_table = bfd_ardata (arch_bfd)->cache; + + /* If the hash table hasn't been created, create it. */ + if (hash_table == NULL) + { + hash_table = htab_create_alloc (16, hash_file_ptr, eq_file_ptr, + NULL, calloc, free); + if (hash_table == NULL) + return FALSE; + bfd_ardata (arch_bfd)->cache = hash_table; + } + + /* Insert new_elt into the hash table by filepos. */ + cache = bfd_zalloc (arch_bfd, sizeof (struct ar_cache)); + cache->ptr = filepos; + cache->arbfd = new_elt; + *htab_find_slot (hash_table, (const void *) cache, INSERT) = 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 (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 || index >= bfd_ardata (arch)->extended_names_size) + { + 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. */ + +void * +_bfd_generic_read_ar_hdr (bfd *abfd) +{ + return _bfd_generic_read_ar_hdr_mag (abfd, 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. */ + +void * +_bfd_generic_read_ar_hdr_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 (hdrp, 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) + 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 = memchr (hdr.ar_name, '\0', ar_maxnamelen (abfd)); + if (e == NULL) + { + e = memchr (hdr.ar_name, '/', ar_maxnamelen (abfd)); + if (e == NULL) + e = 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 (ared->arch_header, &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, namelen); + ared->filename[namelen] = '\0'; + } + + return 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 (bfd *archive, file_ptr filepos) +{ + struct areltdata *new_areldata; + bfd *n_nfd; + + if (archive->my_archive) + { + filepos += archive->origin; + archive = archive->my_archive; + } + + 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 = _bfd_read_ar_hdr (archive)) == NULL) + return NULL; + + n_nfd = _bfd_create_empty_archive_element_shell (archive); + if (n_nfd == NULL) + { + bfd_release (archive, new_areldata); + return NULL; + } + + n_nfd->origin = bfd_tell (archive); + n_nfd->arelt_data = 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, n_nfd); + bfd_release (archive, 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 (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 (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 (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); + filestart = last_file->origin + size; + if (archive->my_archive) + filestart -= archive->origin; + /* 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 += filestart % 2; + } + + return _bfd_get_elt_at_filepos (archive, filestart); +} + +const bfd_target * +bfd_generic_archive_p (bfd *abfd) +{ + struct artdata *tdata_hold; + char armag[SARMAG + 1]; + bfd_size_type amt; + + if (bfd_bread (armag, SARMAG, abfd) != SARMAG) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + if (strncmp (armag, ARMAG, SARMAG) != 0 && + strncmp (armag, ARMAGB, SARMAG) != 0) + return 0; + + tdata_hold = bfd_ardata (abfd); + + amt = sizeof (struct artdata); + bfd_ardata (abfd) = bfd_zalloc (abfd, amt); + if (bfd_ardata (abfd) == NULL) + { + bfd_ardata (abfd) = tdata_hold; + return NULL; + } + + bfd_ardata (abfd)->first_file_filepos = SARMAG; + /* Cleared by bfd_zalloc above. + 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)->extended_names_size = 0; + 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, NULL); + if (first != NULL) + { + bfd_boolean fail; + + first->target_defaulted = FALSE; + fail = FALSE; + if (bfd_check_format (first, bfd_object) + && first->xvec != abfd->xvec) + { + 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 (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 = _bfd_read_ar_hdr (abfd); + if (mapdata == NULL) + return FALSE; + parsed_size = mapdata->parsed_size; + bfd_release (abfd, mapdata); /* Don't need it any more. */ + + raw_armap = bfd_zalloc (abfd, parsed_size); + if (raw_armap == NULL) + return FALSE; + + if (bfd_bread (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, 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 = ardata->symdef_count * sizeof (carsym); + ardata->symdefs = 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 (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) (const void *); + char int_buf[sizeof (long)]; + bfd_size_type carsym_size, ptrsize; + unsigned int i; + + mapdata = _bfd_read_ar_hdr (abfd); + if (mapdata == NULL) + return FALSE; + parsed_size = mapdata->parsed_size; + bfd_release (abfd, mapdata); /* Don't need it any more. */ + + if (bfd_bread (int_buf, 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 (int_buf); + stringsize = parsed_size - (4 * nsymz) - 4; + + /* ... 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 (int_buf); + stringsize = parsed_size - (4 * nsymz) - 4; + swap = bfd_getl32; + } + + /* The coff armap must be read sequentially. So we construct a + bsd-style one in core all at once, for simplicity. */ + + if (nsymz > ~ (bfd_size_type) 0 / sizeof (carsym)) + return FALSE; + + carsym_size = (nsymz * sizeof (carsym)); + ptrsize = (4 * nsymz); + + if (carsym_size + stringsize + 1 <= carsym_size) + return FALSE; + + ardata->symdefs = 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 = 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; + } + + /* OK, build the carsyms. */ + for (i = 0; i < nsymz; i++) + { + rawptr = raw_armap + i; + carsyms->file_offset = swap ((bfd_byte *) 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, 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 = _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, raw_armap); +release_symdefs: + bfd_release (abfd, (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 (bfd *abfd) +{ + char nextname[17]; + int i = bfd_bread (nextname, 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 + extern bfd_boolean bfd_elf64_archive_slurp_armap (bfd *); + 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 (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 (nextname, 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 = _bfd_read_ar_hdr (abfd); + if (mapdata == NULL) + return FALSE; + + amt = mapdata->parsed_size; + raw_armap = bfd_zalloc (abfd, amt); + if (raw_armap == NULL) + { + byebye: + bfd_release (abfd, mapdata); + return FALSE; + } + + if (bfd_bread (raw_armap, amt, abfd) != amt) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + byebyebye: + bfd_release (abfd, raw_armap); + goto byebye; + } + + ardata->symdef_count = H_GET_16 (abfd, 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 = ardata->symdef_count * BSD_SYMDEF_SIZE; + ardata->symdefs = 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 (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 (nextname, 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; + bfd_ardata (abfd)->extended_names_size = 0; + return TRUE; + } + + namedata = _bfd_read_ar_hdr (abfd); + if (namedata == NULL) + return FALSE; + + amt = namedata->parsed_size; + if (amt + 1 == 0) + goto byebye; + + bfd_ardata (abfd)->extended_names_size = amt; + bfd_ardata (abfd)->extended_names = bfd_zalloc (abfd, amt + 1); + if (bfd_ardata (abfd)->extended_names == NULL) + { + byebye: + bfd_release (abfd, namedata); + return FALSE; + } + + if (bfd_bread (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, (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 *ext_names = bfd_ardata (abfd)->extended_names; + char *temp = ext_names; + char *limit = temp + namedata->parsed_size; + for (; temp < limit; ++temp) + { + if (*temp == '\012') + temp[temp > ext_names && temp[-1] == '/' ? -1 : 0] = '\0'; + if (*temp == '\\') + *temp = '/'; + } + *limit = '\0'; + } + + /* 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... */ + } + return TRUE; +} + +#ifdef VMS + +/* Return a copy of the stuff in the filename between any :]> and a + semicolon. */ + +static const char * +normalize (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 = bfd_alloc (abfd, last - first + 1); + if (copy == NULL) + return NULL; + + memcpy (copy, first, last - first); + copy[last - first] = 0; + + return copy; +} + +#else +static const char * +normalize (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 != NULL) + filename++; + else + filename = file; + return filename; +} +#endif + +/* Build a BFD style extended name table. */ + +bfd_boolean +_bfd_archive_bsd_construct_extended_name_table (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 (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 (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); + _bfd_ar_spacepad (hdr->ar_name + 1, maxname - 1, "%-ld", + strptr - *tabloc); + 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 (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 (bfd *abfd, const char *filename, bfd *member) +{ + struct stat status; + struct areltdata *ared; + struct ar_hdr *hdr; + 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 = 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 = 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 (hdr, ' ', sizeof (struct ar_hdr)); + + _bfd_ar_spacepad (hdr->ar_date, sizeof (hdr->ar_date), "%-12ld", + 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_uid, (long) status.st_uid); + else +#endif + _bfd_ar_spacepad (hdr->ar_uid, sizeof (hdr->ar_uid), "%ld", + 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_gid, (long) status.st_gid); + else +#endif + _bfd_ar_spacepad (hdr->ar_gid, sizeof (hdr->ar_gid), "%ld", + status.st_gid); + _bfd_ar_spacepad (hdr->ar_mode, sizeof (hdr->ar_mode), "%-8lo", + status.st_mode); + _bfd_ar_spacepad (hdr->ar_size, sizeof (hdr->ar_size), "%-10ld", + status.st_size); + memcpy (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 (bfd *, const char *); + +struct ar_hdr * +bfd_special_undocumented_glue (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 (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 (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 (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 (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 (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; + 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 = + 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))) + 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; + wrote = bfd_bwrite (ARMAG, SARMAG, arch); + 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 (&hdr, ' ', sizeof (struct ar_hdr)); + memcpy (hdr.ar_name, ename, strlen (ename)); + /* Round size up to even number in archive header. */ + _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld", + (elength + 1) & ~(bfd_size_type) 1); + memcpy (hdr.ar_fmag, ARFMAG, 2); + if ((bfd_bwrite (&hdr, 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", 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 (hdr, 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, amt, current) != amt) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + return FALSE; + } + if (bfd_bwrite (buffer, amt, arch) != amt) + return FALSE; + remaining -= amt; + } + if ((arelt_size (current) % 2) == 1) + { + if (bfd_bwrite ("\012", 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 (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; + 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 = orl_max * sizeof (struct orl); + map = 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, 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 != 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 = bfd_malloc (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 = orl_max * sizeof (struct orl); + new_map = bfd_realloc (map, amt); + if (new_map == NULL) + goto error_return; + + map = new_map; + } + + namelen = strlen (syms[src_count]->name); + amt = sizeof (char *); + map[orl_count].name = 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 (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; + + firstreal = mapsize + elength + sizeof (struct ar_hdr) + SARMAG; + + stat (arch->filename, &statbuf); + memset (&hdr, ' ', sizeof (struct ar_hdr)); + memcpy (hdr.ar_name, RANLIBMAG, strlen (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])); + _bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld", + bfd_ardata (arch)->armap_timestamp); + _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", getuid ()); + _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", getgid ()); + _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld", mapsize); + memcpy (hdr.ar_fmag, ARFMAG, 2); + if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch) + != sizeof (struct ar_hdr)) + return FALSE; + H_PUT_32 (arch, ranlibsize, temp); + if (bfd_bwrite (temp, 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); + } + + 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, BSD_SYMDEF_SIZE, arch) + != BSD_SYMDEF_SIZE) + return FALSE; + } + + /* Now write the strings themselves. */ + H_PUT_32 (arch, stringsize, temp); + if (bfd_bwrite (temp, 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, 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 ("", 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 (bfd *arch) +{ + struct stat archstat; + struct ar_hdr hdr; + + /* 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, ' ', sizeof (hdr.ar_date)); + _bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld", + bfd_ardata (arch)->armap_timestamp); + + /* 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, 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 (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; + 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 (&hdr, ' ', sizeof (struct ar_hdr)); + hdr.ar_name[0] = '/'; + _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld", + mapsize); + _bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld", + time (NULL)); + /* This, at least, is what Intel coff sets the values to. */ + _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", 0); + _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", 0); + _bfd_ar_spacepad (hdr.ar_mode, sizeof (hdr.ar_mode), "%-7lo", 0); + memcpy (hdr.ar_fmag, ARFMAG, 2); + + /* Write the ar header for this item and the number of symbols. */ + if (bfd_bwrite (&hdr, 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 != 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, 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 ("", 1, arch) != 1) + return FALSE; + } + + return TRUE; +} diff --git a/contrib/binutils-2.17/bfd/archive64.c b/contrib/binutils-2.17/bfd/archive64.c new file mode 100644 index 0000000000..3b28f853c2 --- /dev/null +++ b/contrib/binutils-2.17/bfd/archive64.c @@ -0,0 +1,240 @@ +/* MIPS-specific support for 64-bit ELF + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 (bfd *); +bfd_boolean bfd_elf64_archive_write_armap + (bfd *, unsigned int, struct orl *, unsigned int, int); + +/* Read an Irix 6 armap. */ + +bfd_boolean +bfd_elf64_archive_slurp_armap (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 (nextname, 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, mapdata); + + if (bfd_bread (int_buf, 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 = bfd_zalloc (abfd, amt); + if (ardata->symdefs == NULL) + return FALSE; + carsyms = ardata->symdefs; + stringbase = ((char *) ardata->symdefs) + carsym_size; + + raw_armap = 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 (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; + 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 (&hdr, ' ', sizeof (struct ar_hdr)); + memcpy (hdr.ar_name, "/SYM64/", strlen ("/SYM64/")); + _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld", + mapsize); + _bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld", + time (NULL)); + /* This, at least, is what Intel coff sets the values to.: */ + _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", 0); + _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", 0); + _bfd_ar_spacepad (hdr.ar_mode, sizeof (hdr.ar_mode), "%-7lo", 0); + memcpy (hdr.ar_fmag, ARFMAG, 2); + + /* Write the ar header for this item and the number of symbols */ + + if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch) + != sizeof (struct ar_hdr)) + return FALSE; + + bfd_putb64 ((bfd_vma) symbol_count, buf); + if (bfd_bwrite (buf, 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 != 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, 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, 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 ("", 1, arch) != 1) + return FALSE; + --padding; + } + + return TRUE; +} diff --git a/contrib/binutils-2.17/bfd/archures.c b/contrib/binutils-2.17/bfd/archures.c new file mode 100644 index 0000000000..f4080a63a4 --- /dev/null +++ b/contrib/binutils-2.17/bfd/archures.c @@ -0,0 +1,1209 @@ +/* BFD library support routines for architectures. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004, 2005, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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_mcf_isa_a_nodiv 9 +.#define bfd_mach_mcf_isa_a 10 +.#define bfd_mach_mcf_isa_a_mac 11 +.#define bfd_mach_mcf_isa_a_emac 12 +.#define bfd_mach_mcf_isa_aplus 13 +.#define bfd_mach_mcf_isa_aplus_mac 14 +.#define bfd_mach_mcf_isa_aplus_emac 15 +.#define bfd_mach_mcf_isa_b_nousp 16 +.#define bfd_mach_mcf_isa_b_nousp_mac 17 +.#define bfd_mach_mcf_isa_b_nousp_emac 18 +.#define bfd_mach_mcf_isa_b 19 +.#define bfd_mach_mcf_isa_b_mac 20 +.#define bfd_mach_mcf_isa_b_emac 21 +.#define bfd_mach_mcf_isa_b_float 22 +.#define bfd_mach_mcf_isa_b_float_mac 23 +.#define bfd_mach_mcf_isa_b_float_emac 24 +. 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_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) +.{* Nonzero if MACH is a 64 bit sparc architecture. *} +.#define bfd_mach_sparc_64bit_p(mach) \ +. ((mach) >= bfd_mach_sparc_v9 && (mach) != bfd_mach_sparc_v8plusb) +. 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_mips7000 7000 +.#define bfd_mach_mips8000 8000 +.#define bfd_mach_mips9000 9000 +.#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 +.#define bfd_mach_mipsisa64r2 65 +. 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_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 +.#define bfd_mach_h8300sx 6 +.#define bfd_mach_h8300sxn 7 +. 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 *} +.#define bfd_mach_hppa10 10 +.#define bfd_mach_hppa11 11 +.#define bfd_mach_hppa20 20 +.#define bfd_mach_hppa20w 25 +. 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_sh2a 0x2a +.#define bfd_mach_sh2a_nofpu 0x2b +.#define bfd_mach_sh2a_nofpu_or_sh4_nommu_nofpu 0x2a1 +.#define bfd_mach_sh2a_nofpu_or_sh3_nommu 0x2a2 +.#define bfd_mach_sh2a_or_sh4 0x2a3 +.#define bfd_mach_sh2a_or_sh3e 0x2a4 +.#define bfd_mach_sh2e 0x2e +.#define bfd_mach_sh3 0x30 +.#define bfd_mach_sh3_nommu 0x31 +.#define bfd_mach_sh3_dsp 0x3d +.#define bfd_mach_sh3e 0x3e +.#define bfd_mach_sh4 0x40 +.#define bfd_mach_sh4_nofpu 0x41 +.#define bfd_mach_sh4_nommu_nofpu 0x42 +.#define bfd_mach_sh4a 0x4a +.#define bfd_mach_sh4a_nofpu 0x4b +.#define bfd_mach_sh4al_dsp 0x4d +.#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' +.#define bfd_mach_v850e1 '1' +. 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_m32c, {* Renesas M16C/M32C. *} +.#define bfd_mach_m16c 0x75 +.#define bfd_mach_m32c 0x78 +. bfd_arch_m32r, {* Renesas M32R (formerly Mitsubishi M32R/D) *} +.#define bfd_mach_m32r 1 {* For backwards compatibility. *} +.#define bfd_mach_m32rx 'x' +.#define bfd_mach_m32r2 '2' +. bfd_arch_mn10200, {* Matsushita MN10200 *} +. bfd_arch_mn10300, {* Matsushita MN10300 *} +.#define bfd_mach_mn10300 300 +.#define bfd_mach_am33 330 +.#define bfd_mach_am33_2 332 +. 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_fr450 450 +.#define bfd_mach_frvtomcat 499 {* fr500 prototype *} +.#define bfd_mach_fr500 500 +.#define bfd_mach_fr550 550 +. 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_mt, +.#define bfd_mach_ms1 1 +.#define bfd_mach_mrisc2 2 +.#define bfd_mach_ms2 3 +. 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_bfin, {* ADI Blackfin *} +.#define bfd_mach_bfin 1 +. bfd_arch_cr16c, {* National Semiconductor CompactRISC. *} +.#define bfd_mach_cr16c 1 +. bfd_arch_crx, {* National Semiconductor CRX. *} +.#define bfd_mach_crx 1 +. bfd_arch_cris, {* Axis CRIS *} +.#define bfd_mach_cris_v0_v10 255 +.#define bfd_mach_cris_v32 32 +.#define bfd_mach_cris_v10_v32 1032 +. 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_msp11 11 +.#define bfd_mach_msp110 110 +.#define bfd_mach_msp12 12 +.#define bfd_mach_msp13 13 +.#define bfd_mach_msp14 14 +.#define bfd_mach_msp15 15 +.#define bfd_mach_msp16 16 +.#define bfd_mach_msp21 21 +.#define bfd_mach_msp31 31 +.#define bfd_mach_msp32 32 +.#define bfd_mach_msp33 33 +.#define bfd_mach_msp41 41 +.#define bfd_mach_msp42 42 +.#define bfd_mach_msp43 43 +.#define bfd_mach_msp44 44 +. bfd_arch_xc16x, {* Infineon's XC16X Series. *} +.#define bfd_mach_xc16x 1 +.#define bfd_mach_xc16xl 2 +.#define bfd_mach_xc16xs 3 +. bfd_arch_xtensa, {* Tensilica's Xtensa cores. *} +.#define bfd_mach_xtensa 1 +. bfd_arch_maxq, {* Dallas MAXQ 10/20 *} +.#define bfd_mach_maxq10 10 +.#define bfd_mach_maxq20 20 +. bfd_arch_z80, +.#define bfd_mach_z80strict 1 {* No undocumented opcodes. *} +.#define bfd_mach_z80 3 {* With ixl, ixh, iyl, and iyh. *} +.#define bfd_mach_z80full 7 {* All undocumented instructions. *} +.#define bfd_mach_r800 11 {* R800: successor with multiplication. *} +. 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) +. (const struct bfd_arch_info *a, const struct bfd_arch_info *b); +. +. bfd_boolean (*scan) (const struct bfd_arch_info *, const char *); +. +. const struct bfd_arch_info *next; +.} +.bfd_arch_info_type; +. +*/ + +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_bfin_arch; +extern const bfd_arch_info_type bfd_cr16c_arch; +extern const bfd_arch_info_type bfd_cris_arch; +extern const bfd_arch_info_type bfd_crx_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_m32c_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_maxq_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_mt_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_xc16x_arch; +extern const bfd_arch_info_type bfd_z80_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_alpha_arch, + &bfd_arc_arch, + &bfd_arm_arch, + &bfd_avr_arch, + &bfd_bfin_arch, + &bfd_cr16c_arch, + &bfd_cris_arch, + &bfd_crx_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_m32c_arch, + &bfd_m32r_arch, + &bfd_m68hc11_arch, + &bfd_m68hc12_arch, + &bfd_m68k_arch, + &bfd_m88k_arch, + &bfd_maxq_arch, + &bfd_mcore_arch, + &bfd_mips_arch, + &bfd_mmix_arch, + &bfd_mn10200_arch, + &bfd_mn10300_arch, + &bfd_mt_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_xc16x_arch, + &bfd_z80_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 (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 (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 (void) +{ + 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 = 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 (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 (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 (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 (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 (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 (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 (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 (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 (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 ambiguous. 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_mcf_isa_a_nodiv; + break; + case 5206: + arch = bfd_arch_m68k; + number = bfd_mach_mcf_isa_a_mac; + break; + case 5307: + arch = bfd_arch_m68k; + number = bfd_mach_mcf_isa_a_mac; + break; + case 5407: + arch = bfd_arch_m68k; + number = bfd_mach_mcf_isa_b_nousp_mac; + break; + case 5282: + arch = bfd_arch_m68k; + number = bfd_mach_mcf_isa_aplus_emac; + 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 (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 architecture 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 (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 (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 (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 (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.17/bfd/bfd-in.h b/contrib/binutils-2.17/bfd/bfd-in.h new file mode 100644 index 0000000000..9daa578c03 --- /dev/null +++ b/contrib/binutils-2.17/bfd/bfd-in.h @@ -0,0 +1,901 @@ +/* Main header file for the bfd library -- portable access to object files. + + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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@ +#define BFD_HOST_LONG_LONG @BFD_HOST_LONG_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@ +typedef BFD_HOST_64_BIT bfd_int64_t; +typedef BFD_HOST_U_64_BIT bfd_uint64_t; +#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 + +#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 */ + +#define HALF_BFD_SIZE_TYPE \ + (((bfd_size_type) 1) << (8 * sizeof (bfd_size_type) / 2)) + +#ifndef BFD_HOST_64_BIT +/* Fall back on a 32 bit type. The idea is to make these types always + available for function return types, but in the case that + BFD_HOST_64_BIT is undefined such a function should abort or + otherwise signal an error. */ +typedef bfd_signed_vma bfd_int64_t; +typedef bfd_vma bfd_uint64_t; +#endif + +/* An offset into a file. BFD always uses the largest possible offset + based on the build time availability of fseek, fseeko, or fseeko64. */ +typedef @bfd_file_ptr@ file_ptr; +typedef unsigned @bfd_file_ptr@ ufile_ptr; + +extern void bfd_sprintf_vma (bfd *, char *, bfd_vma); +extern void bfd_fprintf_vma (bfd *, void *, 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/assembler/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 + +/* This BFD has been created by the linker and doesn't correspond + to any input file. */ +#define BFD_LINKER_CREATED 0x2000 + +/* 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 bfd_symbol *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 bfd_section *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) ((ptr)->size) +#define bfd_get_section_size(ptr) ((ptr)->size) +#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) +/* Find the address one past the end of SEC. */ +#define bfd_get_section_limit(bfd, sec) \ + (((sec)->rawsize ? (sec)->rawsize : (sec)->size) \ + / bfd_octets_per_byte (bfd)) + +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 (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; + /* The size of elements. */ + unsigned int entsize; + /* 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) + (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); + /* An objalloc for this hash table. This is a struct objalloc *, + but we use void * to avoid requiring the inclusion of objalloc.h. */ + void *memory; +}; + +/* Initialize a hash table. */ +extern bfd_boolean bfd_hash_table_init + (struct bfd_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int); + +/* Initialize a hash table specifying a size. */ +extern bfd_boolean bfd_hash_table_init_n + (struct bfd_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int, unsigned int); + +/* Free up a hash table. */ +extern void bfd_hash_table_free + (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 + (struct bfd_hash_table *, const char *, bfd_boolean create, + bfd_boolean copy); + +/* Replace an entry in a hash table. */ +extern void bfd_hash_replace + (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 + (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); + +/* Grab some space for a hash table entry. */ +extern void *bfd_hash_allocate + (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 + (struct bfd_hash_table *, + bfd_boolean (*) (struct bfd_hash_entry *, void *), + void *info); + +/* Allows the default size of a hash table to be configured. New hash + tables allocated using bfd_hash_table_init will be created with + this size. */ +extern void bfd_hash_set_default_size (bfd_size_type); + +/* 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 bfd_hash_table includes; + /* The first .stabstr section. */ + struct bfd_section *stabstr; +}; + +#define COFF_SWAP_TABLE (void *) &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 (void *, bfd_size_type, bfd *); +extern bfd_size_type bfd_bwrite (const void *, bfd_size_type, bfd *); +extern int bfd_seek (bfd *, file_ptr, int); +extern file_ptr bfd_tell (bfd *); +extern int bfd_flush (bfd *); +extern int bfd_stat (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 (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 + (bfd *abfd); +/* NB: This declaration should match the autogenerated one in libbfd.h. */ + +extern bfd_boolean bfd_cache_close_all (void); + +extern bfd_boolean bfd_record_phdr + (bfd *, unsigned long, bfd_boolean, flagword, bfd_boolean, bfd_vma, + bfd_boolean, bfd_boolean, unsigned int, struct bfd_section **); + +/* Byte swapping routines. */ + +bfd_uint64_t bfd_getb64 (const void *); +bfd_uint64_t bfd_getl64 (const void *); +bfd_int64_t bfd_getb_signed_64 (const void *); +bfd_int64_t bfd_getl_signed_64 (const void *); +bfd_vma bfd_getb32 (const void *); +bfd_vma bfd_getl32 (const void *); +bfd_signed_vma bfd_getb_signed_32 (const void *); +bfd_signed_vma bfd_getl_signed_32 (const void *); +bfd_vma bfd_getb16 (const void *); +bfd_vma bfd_getl16 (const void *); +bfd_signed_vma bfd_getb_signed_16 (const void *); +bfd_signed_vma bfd_getl_signed_16 (const void *); +void bfd_putb64 (bfd_uint64_t, void *); +void bfd_putl64 (bfd_uint64_t, void *); +void bfd_putb32 (bfd_vma, void *); +void bfd_putl32 (bfd_vma, void *); +void bfd_putb16 (bfd_vma, void *); +void bfd_putl16 (bfd_vma, void *); + +/* Byte swapping routines which take size and endiannes as arguments. */ + +bfd_uint64_t bfd_get_bits (const void *, int, bfd_boolean); +void bfd_put_bits (bfd_uint64_t, void *, int, bfd_boolean); + +extern bfd_boolean bfd_section_already_linked_table_init (void); +extern void bfd_section_already_linked_table_free (void); + +/* Externally visible ECOFF routines. */ + +#if defined(__STDC__) || defined(ALMOST_STDC) +struct ecoff_debug_info; +struct ecoff_debug_swap; +struct ecoff_extr; +struct bfd_symbol; +struct bfd_link_info; +struct bfd_link_hash_entry; +struct bfd_elf_version_tree; +#endif +extern bfd_vma bfd_ecoff_get_gp_value + (bfd * abfd); +extern bfd_boolean bfd_ecoff_set_gp_value + (bfd *abfd, bfd_vma gp_value); +extern bfd_boolean bfd_ecoff_set_regmasks + (bfd *abfd, unsigned long gprmask, unsigned long fprmask, + unsigned long *cprmask); +extern void *bfd_ecoff_debug_init + (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 + (void *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 + (void *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 + (void *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 + (bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, bfd_boolean relocatable, + bfd_boolean (*get_extr) (struct bfd_symbol *, struct ecoff_extr *), + void (*set_index) (struct bfd_symbol *, bfd_size_type)); +extern bfd_boolean bfd_ecoff_debug_one_external + (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 + (bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap); +extern bfd_boolean bfd_ecoff_write_debug + (bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, file_ptr where); +extern bfd_boolean bfd_ecoff_write_accumulated_debug + (void *handle, bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + struct bfd_link_info *info, file_ptr where); + +/* Externally visible ELF routines. */ + +struct bfd_link_needed_list +{ + struct bfd_link_needed_list *next; + bfd *by; + const char *name; +}; + +enum dynamic_lib_link_class { + DYN_NORMAL = 0, + DYN_AS_NEEDED = 1, + DYN_DT_NEEDED = 2, + DYN_NO_ADD_NEEDED = 4, + DYN_NO_NEEDED = 8 +}; + +extern bfd_boolean bfd_elf_record_link_assignment + (bfd *, struct bfd_link_info *, const char *, bfd_boolean, + bfd_boolean); +extern struct bfd_link_needed_list *bfd_elf_get_needed_list + (bfd *, struct bfd_link_info *); +extern bfd_boolean bfd_elf_get_bfd_needed_list + (bfd *, struct bfd_link_needed_list **); +extern bfd_boolean bfd_elf_size_dynamic_sections + (bfd *, const char *, const char *, const char *, const char * const *, + struct bfd_link_info *, struct bfd_section **, + struct bfd_elf_version_tree *); +extern bfd_boolean bfd_elf_size_dynsym_hash_dynstr + (bfd *, struct bfd_link_info *); +extern void bfd_elf_set_dt_needed_name + (bfd *, const char *); +extern const char *bfd_elf_get_dt_soname + (bfd *); +extern void bfd_elf_set_dyn_lib_class + (bfd *, int); +extern int bfd_elf_get_dyn_lib_class + (bfd *); +extern struct bfd_link_needed_list *bfd_elf_get_runpath_list + (bfd *, struct bfd_link_info *); +extern bfd_boolean bfd_elf_discard_info + (bfd *, struct bfd_link_info *); +extern unsigned int _bfd_elf_default_action_discarded + (struct bfd_section *); + +/* 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 + (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 + (bfd *abfd, void *phdrs); + +/* Create a new BFD as if by bfd_openr. Rather than opening a file, + reconstruct an ELF file by reading the segments out of remote memory + based on the ELF file header at EHDR_VMA and the ELF program headers it + points to. If not null, *LOADBASEP is filled in with the difference + between the VMAs from which the segments were read, and the VMAs the + file headers (and hence BFD's idea of each section's VMA) put them at. + + The function TARGET_READ_MEMORY is called to copy LEN bytes from the + remote memory at target address VMA into the local buffer at MYADDR; it + should return zero on success or an `errno' code on failure. TEMPL must + be a BFD for an ELF target with the word size and byte order found in + the remote memory. */ +extern bfd *bfd_elf_bfd_from_remote_memory + (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, + int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, int len)); + +/* Return the arch_size field of an elf bfd, or -1 if not elf. */ +extern int bfd_get_arch_size + (bfd *); + +/* Return TRUE if address "naturally" sign extends, or -1 if not elf. */ +extern int bfd_get_sign_extend_vma + (bfd *); + +extern struct bfd_section *_bfd_elf_tls_setup + (bfd *, struct bfd_link_info *); + +extern void _bfd_fix_excluded_sec_syms + (bfd *, struct bfd_link_info *); + +extern unsigned bfd_m68k_mach_to_features (int); + +extern int bfd_m68k_features_to_mach (unsigned); + +extern bfd_boolean bfd_m68k_elf32_create_embedded_relocs + (bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, + char **); + +extern bfd_boolean bfd_bfin_elf32_create_embedded_relocs + (bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, + char **); + +/* SunOS shared library support routines for the linker. */ + +extern struct bfd_link_needed_list *bfd_sunos_get_needed_list + (bfd *, struct bfd_link_info *); +extern bfd_boolean bfd_sunos_record_link_assignment + (bfd *, struct bfd_link_info *, const char *); +extern bfd_boolean bfd_sunos_size_dynamic_sections + (bfd *, struct bfd_link_info *, struct bfd_section **, + struct bfd_section **, struct bfd_section **); + +/* Linux shared library support routines for the linker. */ + +extern bfd_boolean bfd_i386linux_size_dynamic_sections + (bfd *, struct bfd_link_info *); +extern bfd_boolean bfd_m68klinux_size_dynamic_sections + (bfd *, struct bfd_link_info *); +extern bfd_boolean bfd_sparclinux_size_dynamic_sections + (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. */ + void *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 + (bfd_window *); +extern void bfd_free_window + (bfd_window *); +extern bfd_boolean bfd_get_file_window + (bfd *, file_ptr, bfd_size_type, bfd_window *, bfd_boolean); + +/* XCOFF support routines for the linker. */ + +extern bfd_boolean bfd_xcoff_link_record_set + (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, bfd_size_type); +extern bfd_boolean bfd_xcoff_import_symbol + (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 + (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *); +extern bfd_boolean bfd_xcoff_link_count_reloc + (bfd *, struct bfd_link_info *, const char *); +extern bfd_boolean bfd_xcoff_record_link_assignment + (bfd *, struct bfd_link_info *, const char *); +extern bfd_boolean bfd_xcoff_size_dynamic_sections + (bfd *, struct bfd_link_info *, const char *, const char *, + unsigned long, unsigned long, unsigned long, bfd_boolean, + int, bfd_boolean, bfd_boolean, struct bfd_section **, bfd_boolean); +extern bfd_boolean bfd_xcoff_link_generate_rtinit + (bfd *, const char *, const char *, bfd_boolean); + +/* XCOFF support routines for ar. */ +extern bfd_boolean bfd_xcoff_ar_archive_set_magic + (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 + (bfd *, struct bfd_symbol *, struct internal_syment *); + +extern bfd_boolean bfd_coff_get_auxent + (bfd *, struct bfd_symbol *, int, union internal_auxent *); + +extern bfd_boolean bfd_coff_set_symbol_class + (bfd *, struct bfd_symbol *, unsigned int); + +extern bfd_boolean bfd_m68k_coff_create_embedded_relocs + (bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, char **); + +/* ARM Interworking support. Called from linker. */ +extern bfd_boolean bfd_arm_allocate_interworking_sections + (struct bfd_link_info *); + +extern bfd_boolean bfd_arm_process_before_allocation + (bfd *, struct bfd_link_info *, int); + +extern bfd_boolean bfd_arm_get_bfd_for_interworking + (bfd *, struct bfd_link_info *); + +/* PE ARM Interworking support. Called from linker. */ +extern bfd_boolean bfd_arm_pe_allocate_interworking_sections + (struct bfd_link_info *); + +extern bfd_boolean bfd_arm_pe_process_before_allocation + (bfd *, struct bfd_link_info *, int); + +extern bfd_boolean bfd_arm_pe_get_bfd_for_interworking + (bfd *, struct bfd_link_info *); + +/* ELF ARM Interworking support. Called from linker. */ +extern bfd_boolean bfd_elf32_arm_allocate_interworking_sections + (struct bfd_link_info *); + +extern bfd_boolean bfd_elf32_arm_process_before_allocation + (bfd *, struct bfd_link_info *, int); + +void bfd_elf32_arm_set_target_relocs + (struct bfd_link_info *, int, char *, int, int); + +extern bfd_boolean bfd_elf32_arm_get_bfd_for_interworking + (bfd *, struct bfd_link_info *); + +extern bfd_boolean bfd_elf32_arm_add_glue_sections_to_bfd + (bfd *, struct bfd_link_info *); + +/* ELF ARM mapping symbol support */ +extern bfd_boolean bfd_is_arm_mapping_symbol_name + (const char * name); + +/* ARM Note section processing. */ +extern bfd_boolean bfd_arm_merge_machines + (bfd *, bfd *); + +extern bfd_boolean bfd_arm_update_notes + (bfd *, const char *); + +extern unsigned int bfd_arm_get_mach_from_notes + (bfd *, const char *); + +/* TI COFF load page support. */ +extern void bfd_ticoff_set_section_load_page + (struct bfd_section *, int); + +extern int bfd_ticoff_get_section_load_page + (struct bfd_section *); + +/* H8/300 functions. */ +extern bfd_vma bfd_h8300_pad_address + (bfd *, bfd_vma); + +/* IA64 Itanium code generation. Called from linker. */ +extern void bfd_elf32_ia64_after_parse + (int); + +extern void bfd_elf64_ia64_after_parse + (int); + +/* This structure is used for a comdat section, as in PE. A comdat + section is associated with a particular symbol. When the linker + sees a comdat section, it keeps only one of the sections with a + given name and associated with a given symbol. */ + +struct coff_comdat_info +{ + /* The name of the symbol associated with a comdat section. */ + const char *name; + + /* The local symbol table index of the symbol associated with a + comdat section. This is only meaningful to the object file format + specific code; it is not an index into the list returned by + bfd_canonicalize_symtab. */ + long symbol; +}; + +extern struct coff_comdat_info *bfd_coff_get_comdat_section + (bfd *, struct bfd_section *); + diff --git a/contrib/binutils-2.17/bfd/bfd-in2.h b/contrib/binutils-2.17/bfd/bfd-in2.h new file mode 100644 index 0000000000..63fb521b0a --- /dev/null +++ b/contrib/binutils-2.17/bfd/bfd-in2.h @@ -0,0 +1,5140 @@ +/* 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, 2004, 2005, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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@ +#define BFD_HOST_LONG_LONG @BFD_HOST_LONG_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@ +typedef BFD_HOST_64_BIT bfd_int64_t; +typedef BFD_HOST_U_64_BIT bfd_uint64_t; +#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 + +#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 */ + +#define HALF_BFD_SIZE_TYPE \ + (((bfd_size_type) 1) << (8 * sizeof (bfd_size_type) / 2)) + +#ifndef BFD_HOST_64_BIT +/* Fall back on a 32 bit type. The idea is to make these types always + available for function return types, but in the case that + BFD_HOST_64_BIT is undefined such a function should abort or + otherwise signal an error. */ +typedef bfd_signed_vma bfd_int64_t; +typedef bfd_vma bfd_uint64_t; +#endif + +/* An offset into a file. BFD always uses the largest possible offset + based on the build time availability of fseek, fseeko, or fseeko64. */ +typedef @bfd_file_ptr@ file_ptr; +typedef unsigned @bfd_file_ptr@ ufile_ptr; + +extern void bfd_sprintf_vma (bfd *, char *, bfd_vma); +extern void bfd_fprintf_vma (bfd *, void *, 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/assembler/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 + +/* This BFD has been created by the linker and doesn't correspond + to any input file. */ +#define BFD_LINKER_CREATED 0x2000 + +/* 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 bfd_symbol *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 bfd_section *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) ((ptr)->size) +#define bfd_get_section_size(ptr) ((ptr)->size) +#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) +/* Find the address one past the end of SEC. */ +#define bfd_get_section_limit(bfd, sec) \ + (((sec)->rawsize ? (sec)->rawsize : (sec)->size) \ + / bfd_octets_per_byte (bfd)) + +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 (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; + /* The size of elements. */ + unsigned int entsize; + /* 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) + (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); + /* An objalloc for this hash table. This is a struct objalloc *, + but we use void * to avoid requiring the inclusion of objalloc.h. */ + void *memory; +}; + +/* Initialize a hash table. */ +extern bfd_boolean bfd_hash_table_init + (struct bfd_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int); + +/* Initialize a hash table specifying a size. */ +extern bfd_boolean bfd_hash_table_init_n + (struct bfd_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int, unsigned int); + +/* Free up a hash table. */ +extern void bfd_hash_table_free + (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 + (struct bfd_hash_table *, const char *, bfd_boolean create, + bfd_boolean copy); + +/* Replace an entry in a hash table. */ +extern void bfd_hash_replace + (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 + (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); + +/* Grab some space for a hash table entry. */ +extern void *bfd_hash_allocate + (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 + (struct bfd_hash_table *, + bfd_boolean (*) (struct bfd_hash_entry *, void *), + void *info); + +/* Allows the default size of a hash table to be configured. New hash + tables allocated using bfd_hash_table_init will be created with + this size. */ +extern void bfd_hash_set_default_size (bfd_size_type); + +/* 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 bfd_hash_table includes; + /* The first .stabstr section. */ + struct bfd_section *stabstr; +}; + +#define COFF_SWAP_TABLE (void *) &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 (void *, bfd_size_type, bfd *); +extern bfd_size_type bfd_bwrite (const void *, bfd_size_type, bfd *); +extern int bfd_seek (bfd *, file_ptr, int); +extern file_ptr bfd_tell (bfd *); +extern int bfd_flush (bfd *); +extern int bfd_stat (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 (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 + (bfd *abfd); +/* NB: This declaration should match the autogenerated one in libbfd.h. */ + +extern bfd_boolean bfd_cache_close_all (void); + +extern bfd_boolean bfd_record_phdr + (bfd *, unsigned long, bfd_boolean, flagword, bfd_boolean, bfd_vma, + bfd_boolean, bfd_boolean, unsigned int, struct bfd_section **); + +/* Byte swapping routines. */ + +bfd_uint64_t bfd_getb64 (const void *); +bfd_uint64_t bfd_getl64 (const void *); +bfd_int64_t bfd_getb_signed_64 (const void *); +bfd_int64_t bfd_getl_signed_64 (const void *); +bfd_vma bfd_getb32 (const void *); +bfd_vma bfd_getl32 (const void *); +bfd_signed_vma bfd_getb_signed_32 (const void *); +bfd_signed_vma bfd_getl_signed_32 (const void *); +bfd_vma bfd_getb16 (const void *); +bfd_vma bfd_getl16 (const void *); +bfd_signed_vma bfd_getb_signed_16 (const void *); +bfd_signed_vma bfd_getl_signed_16 (const void *); +void bfd_putb64 (bfd_uint64_t, void *); +void bfd_putl64 (bfd_uint64_t, void *); +void bfd_putb32 (bfd_vma, void *); +void bfd_putl32 (bfd_vma, void *); +void bfd_putb16 (bfd_vma, void *); +void bfd_putl16 (bfd_vma, void *); + +/* Byte swapping routines which take size and endiannes as arguments. */ + +bfd_uint64_t bfd_get_bits (const void *, int, bfd_boolean); +void bfd_put_bits (bfd_uint64_t, void *, int, bfd_boolean); + +extern bfd_boolean bfd_section_already_linked_table_init (void); +extern void bfd_section_already_linked_table_free (void); + +/* Externally visible ECOFF routines. */ + +#if defined(__STDC__) || defined(ALMOST_STDC) +struct ecoff_debug_info; +struct ecoff_debug_swap; +struct ecoff_extr; +struct bfd_symbol; +struct bfd_link_info; +struct bfd_link_hash_entry; +struct bfd_elf_version_tree; +#endif +extern bfd_vma bfd_ecoff_get_gp_value + (bfd * abfd); +extern bfd_boolean bfd_ecoff_set_gp_value + (bfd *abfd, bfd_vma gp_value); +extern bfd_boolean bfd_ecoff_set_regmasks + (bfd *abfd, unsigned long gprmask, unsigned long fprmask, + unsigned long *cprmask); +extern void *bfd_ecoff_debug_init + (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 + (void *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 + (void *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 + (void *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 + (bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, bfd_boolean relocatable, + bfd_boolean (*get_extr) (struct bfd_symbol *, struct ecoff_extr *), + void (*set_index) (struct bfd_symbol *, bfd_size_type)); +extern bfd_boolean bfd_ecoff_debug_one_external + (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 + (bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap); +extern bfd_boolean bfd_ecoff_write_debug + (bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, file_ptr where); +extern bfd_boolean bfd_ecoff_write_accumulated_debug + (void *handle, bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + struct bfd_link_info *info, file_ptr where); + +/* Externally visible ELF routines. */ + +struct bfd_link_needed_list +{ + struct bfd_link_needed_list *next; + bfd *by; + const char *name; +}; + +enum dynamic_lib_link_class { + DYN_NORMAL = 0, + DYN_AS_NEEDED = 1, + DYN_DT_NEEDED = 2, + DYN_NO_ADD_NEEDED = 4, + DYN_NO_NEEDED = 8 +}; + +extern bfd_boolean bfd_elf_record_link_assignment + (bfd *, struct bfd_link_info *, const char *, bfd_boolean, + bfd_boolean); +extern struct bfd_link_needed_list *bfd_elf_get_needed_list + (bfd *, struct bfd_link_info *); +extern bfd_boolean bfd_elf_get_bfd_needed_list + (bfd *, struct bfd_link_needed_list **); +extern bfd_boolean bfd_elf_size_dynamic_sections + (bfd *, const char *, const char *, const char *, const char * const *, + struct bfd_link_info *, struct bfd_section **, + struct bfd_elf_version_tree *); +extern bfd_boolean bfd_elf_size_dynsym_hash_dynstr + (bfd *, struct bfd_link_info *); +extern void bfd_elf_set_dt_needed_name + (bfd *, const char *); +extern const char *bfd_elf_get_dt_soname + (bfd *); +extern void bfd_elf_set_dyn_lib_class + (bfd *, int); +extern int bfd_elf_get_dyn_lib_class + (bfd *); +extern struct bfd_link_needed_list *bfd_elf_get_runpath_list + (bfd *, struct bfd_link_info *); +extern bfd_boolean bfd_elf_discard_info + (bfd *, struct bfd_link_info *); +extern unsigned int _bfd_elf_default_action_discarded + (struct bfd_section *); + +/* 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 + (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 + (bfd *abfd, void *phdrs); + +/* Create a new BFD as if by bfd_openr. Rather than opening a file, + reconstruct an ELF file by reading the segments out of remote memory + based on the ELF file header at EHDR_VMA and the ELF program headers it + points to. If not null, *LOADBASEP is filled in with the difference + between the VMAs from which the segments were read, and the VMAs the + file headers (and hence BFD's idea of each section's VMA) put them at. + + The function TARGET_READ_MEMORY is called to copy LEN bytes from the + remote memory at target address VMA into the local buffer at MYADDR; it + should return zero on success or an `errno' code on failure. TEMPL must + be a BFD for an ELF target with the word size and byte order found in + the remote memory. */ +extern bfd *bfd_elf_bfd_from_remote_memory + (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, + int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, int len)); + +/* Return the arch_size field of an elf bfd, or -1 if not elf. */ +extern int bfd_get_arch_size + (bfd *); + +/* Return TRUE if address "naturally" sign extends, or -1 if not elf. */ +extern int bfd_get_sign_extend_vma + (bfd *); + +extern struct bfd_section *_bfd_elf_tls_setup + (bfd *, struct bfd_link_info *); + +extern void _bfd_fix_excluded_sec_syms + (bfd *, struct bfd_link_info *); + +extern unsigned bfd_m68k_mach_to_features (int); + +extern int bfd_m68k_features_to_mach (unsigned); + +extern bfd_boolean bfd_m68k_elf32_create_embedded_relocs + (bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, + char **); + +extern bfd_boolean bfd_bfin_elf32_create_embedded_relocs + (bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, + char **); + +/* SunOS shared library support routines for the linker. */ + +extern struct bfd_link_needed_list *bfd_sunos_get_needed_list + (bfd *, struct bfd_link_info *); +extern bfd_boolean bfd_sunos_record_link_assignment + (bfd *, struct bfd_link_info *, const char *); +extern bfd_boolean bfd_sunos_size_dynamic_sections + (bfd *, struct bfd_link_info *, struct bfd_section **, + struct bfd_section **, struct bfd_section **); + +/* Linux shared library support routines for the linker. */ + +extern bfd_boolean bfd_i386linux_size_dynamic_sections + (bfd *, struct bfd_link_info *); +extern bfd_boolean bfd_m68klinux_size_dynamic_sections + (bfd *, struct bfd_link_info *); +extern bfd_boolean bfd_sparclinux_size_dynamic_sections + (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. */ + void *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 + (bfd_window *); +extern void bfd_free_window + (bfd_window *); +extern bfd_boolean bfd_get_file_window + (bfd *, file_ptr, bfd_size_type, bfd_window *, bfd_boolean); + +/* XCOFF support routines for the linker. */ + +extern bfd_boolean bfd_xcoff_link_record_set + (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, bfd_size_type); +extern bfd_boolean bfd_xcoff_import_symbol + (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 + (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *); +extern bfd_boolean bfd_xcoff_link_count_reloc + (bfd *, struct bfd_link_info *, const char *); +extern bfd_boolean bfd_xcoff_record_link_assignment + (bfd *, struct bfd_link_info *, const char *); +extern bfd_boolean bfd_xcoff_size_dynamic_sections + (bfd *, struct bfd_link_info *, const char *, const char *, + unsigned long, unsigned long, unsigned long, bfd_boolean, + int, bfd_boolean, bfd_boolean, struct bfd_section **, bfd_boolean); +extern bfd_boolean bfd_xcoff_link_generate_rtinit + (bfd *, const char *, const char *, bfd_boolean); + +/* XCOFF support routines for ar. */ +extern bfd_boolean bfd_xcoff_ar_archive_set_magic + (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 + (bfd *, struct bfd_symbol *, struct internal_syment *); + +extern bfd_boolean bfd_coff_get_auxent + (bfd *, struct bfd_symbol *, int, union internal_auxent *); + +extern bfd_boolean bfd_coff_set_symbol_class + (bfd *, struct bfd_symbol *, unsigned int); + +extern bfd_boolean bfd_m68k_coff_create_embedded_relocs + (bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, char **); + +/* ARM Interworking support. Called from linker. */ +extern bfd_boolean bfd_arm_allocate_interworking_sections + (struct bfd_link_info *); + +extern bfd_boolean bfd_arm_process_before_allocation + (bfd *, struct bfd_link_info *, int); + +extern bfd_boolean bfd_arm_get_bfd_for_interworking + (bfd *, struct bfd_link_info *); + +/* PE ARM Interworking support. Called from linker. */ +extern bfd_boolean bfd_arm_pe_allocate_interworking_sections + (struct bfd_link_info *); + +extern bfd_boolean bfd_arm_pe_process_before_allocation + (bfd *, struct bfd_link_info *, int); + +extern bfd_boolean bfd_arm_pe_get_bfd_for_interworking + (bfd *, struct bfd_link_info *); + +/* ELF ARM Interworking support. Called from linker. */ +extern bfd_boolean bfd_elf32_arm_allocate_interworking_sections + (struct bfd_link_info *); + +extern bfd_boolean bfd_elf32_arm_process_before_allocation + (bfd *, struct bfd_link_info *, int); + +void bfd_elf32_arm_set_target_relocs + (struct bfd_link_info *, int, char *, int, int); + +extern bfd_boolean bfd_elf32_arm_get_bfd_for_interworking + (bfd *, struct bfd_link_info *); + +extern bfd_boolean bfd_elf32_arm_add_glue_sections_to_bfd + (bfd *, struct bfd_link_info *); + +/* ELF ARM mapping symbol support */ +extern bfd_boolean bfd_is_arm_mapping_symbol_name + (const char * name); + +/* ARM Note section processing. */ +extern bfd_boolean bfd_arm_merge_machines + (bfd *, bfd *); + +extern bfd_boolean bfd_arm_update_notes + (bfd *, const char *); + +extern unsigned int bfd_arm_get_mach_from_notes + (bfd *, const char *); + +/* TI COFF load page support. */ +extern void bfd_ticoff_set_section_load_page + (struct bfd_section *, int); + +extern int bfd_ticoff_get_section_load_page + (struct bfd_section *); + +/* H8/300 functions. */ +extern bfd_vma bfd_h8300_pad_address + (bfd *, bfd_vma); + +/* IA64 Itanium code generation. Called from linker. */ +extern void bfd_elf32_ia64_after_parse + (int); + +extern void bfd_elf64_ia64_after_parse + (int); + +/* This structure is used for a comdat section, as in PE. A comdat + section is associated with a particular symbol. When the linker + sees a comdat section, it keeps only one of the sections with a + given name and associated with a given symbol. */ + +struct coff_comdat_info +{ + /* The name of the symbol associated with a comdat section. */ + const char *name; + + /* The local symbol table index of the symbol associated with a + comdat section. This is only meaningful to the object file format + specific code; it is not an index into the list returned by + bfd_canonicalize_symtab. */ + long symbol; +}; + +extern struct coff_comdat_info *bfd_coff_get_comdat_section + (bfd *, struct bfd_section *); + +/* Extracted from init.c. */ +void bfd_init (void); + +/* Extracted from opncls.c. */ +bfd *bfd_fopen (const char *filename, const char *target, + const char *mode, int fd); + +bfd *bfd_openr (const char *filename, const char *target); + +bfd *bfd_fdopenr (const char *filename, const char *target, int fd); + +bfd *bfd_openstreamr (const char *, const char *, void *); + +bfd *bfd_openr_iovec (const char *filename, const char *target, + void *(*open) (struct bfd *nbfd, + void *open_closure), + void *open_closure, + file_ptr (*pread) (struct bfd *nbfd, + void *stream, + void *buf, + file_ptr nbytes, + file_ptr offset), + int (*close) (struct bfd *nbfd, + void *stream)); + +bfd *bfd_openw (const char *filename, const char *target); + +bfd_boolean bfd_close (bfd *abfd); + +bfd_boolean bfd_close_all_done (bfd *); + +bfd *bfd_create (const char *filename, bfd *templ); + +bfd_boolean bfd_make_writable (bfd *abfd); + +bfd_boolean bfd_make_readable (bfd *abfd); + +unsigned long bfd_calc_gnu_debuglink_crc32 + (unsigned long crc, const unsigned char *buf, bfd_size_type len); + +char *bfd_follow_gnu_debuglink (bfd *abfd, const char *dir); + +struct bfd_section *bfd_create_gnu_debuglink_section + (bfd *abfd, const char *filename); + +bfd_boolean bfd_fill_in_gnu_debuglink_section + (bfd *abfd, struct bfd_section *sect, const char *filename); + +/* Extracted from libbfd.c. */ + +/* Byte swapping macros for user section data. */ + +#define bfd_put_8(abfd, val, ptr) \ + ((void) (*((unsigned char *) (ptr)) = (val) & 0xff)) +#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)) + +/* Aliases for the above, which should eventually go away. */ + +#define H_PUT_64 bfd_h_put_64 +#define H_PUT_32 bfd_h_put_32 +#define H_PUT_16 bfd_h_put_16 +#define H_PUT_8 bfd_h_put_8 +#define H_PUT_S64 bfd_h_put_signed_64 +#define H_PUT_S32 bfd_h_put_signed_32 +#define H_PUT_S16 bfd_h_put_signed_16 +#define H_PUT_S8 bfd_h_put_signed_8 +#define H_GET_64 bfd_h_get_64 +#define H_GET_32 bfd_h_get_32 +#define H_GET_16 bfd_h_get_16 +#define H_GET_8 bfd_h_get_8 +#define H_GET_S64 bfd_h_get_signed_64 +#define H_GET_S32 bfd_h_get_signed_32 +#define H_GET_S16 bfd_h_get_signed_16 +#define H_GET_S8 bfd_h_get_signed_8 + + +/* Extracted from bfdio.c. */ +long bfd_get_mtime (bfd *abfd); + +long bfd_get_size (bfd *abfd); + +/* Extracted from bfdwin.c. */ +/* Extracted from section.c. */ +typedef struct bfd_section +{ + /* The name of the section; the name isn't a copy, the pointer is + 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 bfd_section *next; + + /* The previous section in the list belonging to the BFD, or NULL. */ + struct bfd_section *prev; + + /* 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 + + /* A signal to the OS that the section contains read only data. */ +#define SEC_READONLY 0x008 + + /* The section contains code only. */ +#define SEC_CODE 0x010 + + /* The section contains data only. */ +#define SEC_DATA 0x020 + + /* The section will reside in ROM. */ +#define SEC_ROM 0x040 + + /* 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 0x080 + + /* The section has contents - a data section could be + <> | <>; a debug section could be + <> */ +#define SEC_HAS_CONTENTS 0x100 + + /* An instruction to the linker to not output the section + even if it has information which would normally be written. */ +#define SEC_NEVER_LOAD 0x200 + + /* The section contains thread local data. */ +#define SEC_THREAD_LOCAL 0x400 + + /* 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 0x800 + + /* 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 0x1000 + + /* 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 0x2000 + + /* 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 0x4000 + + /* 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 0x8000 + + /* 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 0x10000 + + /* 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 0x20000 + + /* If SEC_LINK_ONCE is set, this bitfield describes how the linker + should handle duplicate sections. */ +#define SEC_LINK_DUPLICATES 0x40000 + + /* 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 0x80000 + + /* 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 0x100000 + + /* 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 \ + (SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE) + + /* 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 0x200000 + + /* This section should not be subject to garbage collection. */ +#define SEC_KEEP 0x400000 + + /* This section contains "short" data, and should be placed + "near" the GP. */ +#define SEC_SMALL_DATA 0x800000 + + /* Attempt to merge identical entities in the section. + Entity size is given in the entsize field. */ +#define SEC_MERGE 0x1000000 + + /* 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 0x2000000 + + /* This section contains data about section groups. */ +#define SEC_GROUP 0x4000000 + + /* 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 0x10000000 + + /* This section contains data which may be shared with other + executables or shared objects. This is for COFF only. */ +#define SEC_COFF_SHARED 0x20000000 + + /* 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. This is for TI + TMS320C54X only. */ +#define SEC_TIC54X_BLOCK 0x40000000 + + /* Conditionally link this section; do not link if there are no + references found to any symbol in the section. This is for TI + TMS320C54X only. */ +#define SEC_TIC54X_CLINK 0x80000000 + + /* End of section flags. */ + + /* Some internal packed boolean fields. */ + + /* See the vma field. */ + unsigned int user_set_vma : 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; + + /* Mark flags used by some linker backends for garbage collection. */ + unsigned int gc_mark : 1; + unsigned int gc_mark_from_eh : 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. The generic code doesn't touch + these fields. */ + + /* Nonzero if this section has TLS related relocations. */ + unsigned int has_tls_reloc:1; + + /* Nonzero if this section has a gp reloc. */ + unsigned int has_gp_reloc:1; + + /* Nonzero if this section needs the relax finalize pass. */ + unsigned int need_finalize_relax:1; + + /* Whether relocations have been processed. */ + unsigned int reloc_done : 1; + + /* 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>>). */ + bfd_size_type size; + + /* For input sections, the original size on disk of the section, in + octets. This field is used by the linker relaxation code. It is + currently only set for sections where the linker relaxation scheme + doesn't cache altered section and reloc contents (stabs, eh_frame, + SEC_MERGE, some coff relaxing targets), and thus the original size + needs to be kept to read the section multiple times. + For output sections, rawsize holds the section size calculated on + a previous linker relaxation pass. */ + bfd_size_type rawsize; + + /* 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 bfd_section *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. */ + void *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; + + /* Points to the kept section if this section is a link-once section, + and is discarded. */ + struct bfd_section *kept_section; + + /* 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; + + void *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 bfd_symbol *symbol; + struct bfd_symbol **symbol_ptr_ptr; + + /* Early in the link process, map_head and map_tail are used to build + a list of input sections attached to an output section. Later, + output sections use these fields for a list of bfd_link_order + structs. */ + union { + struct bfd_link_order *link_order; + struct bfd_section *s; + } map_head, map_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 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 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 asection bfd_com_section; +#define bfd_com_section_ptr ((asection *) &bfd_com_section) +/* Pointer to the indirect section. */ +extern 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 bfd_symbol * const bfd_abs_symbol; +extern const struct bfd_symbol * const bfd_com_symbol; +extern const struct bfd_symbol * const bfd_und_symbol; +extern const struct bfd_symbol * const bfd_ind_symbol; + +/* 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, S) \ + do \ + { \ + asection *_s = S; \ + asection *_next = _s->next; \ + asection *_prev = _s->prev; \ + if (_prev) \ + _prev->next = _next; \ + else \ + (ABFD)->sections = _next; \ + if (_next) \ + _next->prev = _prev; \ + else \ + (ABFD)->section_last = _prev; \ + } \ + while (0) +#define bfd_section_list_append(ABFD, S) \ + do \ + { \ + asection *_s = S; \ + bfd *_abfd = ABFD; \ + _s->next = NULL; \ + if (_abfd->section_last) \ + { \ + _s->prev = _abfd->section_last; \ + _abfd->section_last->next = _s; \ + } \ + else \ + { \ + _s->prev = NULL; \ + _abfd->sections = _s; \ + } \ + _abfd->section_last = _s; \ + } \ + while (0) +#define bfd_section_list_prepend(ABFD, S) \ + do \ + { \ + asection *_s = S; \ + bfd *_abfd = ABFD; \ + _s->prev = NULL; \ + if (_abfd->sections) \ + { \ + _s->next = _abfd->sections; \ + _abfd->sections->prev = _s; \ + } \ + else \ + { \ + _s->next = NULL; \ + _abfd->section_last = _s; \ + } \ + _abfd->sections = _s; \ + } \ + while (0) +#define bfd_section_list_insert_after(ABFD, A, S) \ + do \ + { \ + asection *_a = A; \ + asection *_s = S; \ + asection *_next = _a->next; \ + _s->next = _next; \ + _s->prev = _a; \ + _a->next = _s; \ + if (_next) \ + _next->prev = _s; \ + else \ + (ABFD)->section_last = _s; \ + } \ + while (0) +#define bfd_section_list_insert_before(ABFD, B, S) \ + do \ + { \ + asection *_b = B; \ + asection *_s = S; \ + asection *_prev = _b->prev; \ + _s->prev = _prev; \ + _s->next = _b; \ + _b->prev = _s; \ + if (_prev) \ + _prev->next = _s; \ + else \ + (ABFD)->sections = _s; \ + } \ + while (0) +#define bfd_section_removed_from_list(ABFD, S) \ + ((S)->next == NULL ? (ABFD)->section_last != (S) : (S)->next->prev != (S)) + +#define BFD_FAKE_SECTION(SEC, FLAGS, SYM, SYM_PTR, NAME, IDX) \ + /* name, id, index, next, prev, flags, user_set_vma, */ \ + { NAME, IDX, 0, NULL, NULL, FLAGS, 0, \ + \ + /* linker_mark, linker_has_input, gc_mark, gc_mark_from_eh, */ \ + 0, 0, 1, 0, \ + \ + /* segment_mark, sec_info_type, use_rela_p, has_tls_reloc, */ \ + 0, 0, 0, 0, \ + \ + /* has_gp_reloc, need_finalize_relax, reloc_done, */ \ + 0, 0, 0, \ + \ + /* vma, lma, size, rawsize */ \ + 0, 0, 0, 0, \ + \ + /* output_offset, output_section, alignment_power, */ \ + 0, (struct bfd_section *) &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, kept_section, moving_line_filepos, */ \ + 0, NULL, 0, \ + \ + /* target_index, used_by_bfd, constructor_chain, owner, */ \ + 0, NULL, NULL, NULL, \ + \ + /* symbol, */ \ + (struct bfd_symbol *) SYM, \ + \ + /* symbol_ptr_ptr, */ \ + (struct bfd_symbol **) SYM_PTR, \ + \ + /* map_head, map_tail */ \ + { NULL }, { NULL } \ + } + +void bfd_section_list_clear (bfd *); + +asection *bfd_get_section_by_name (bfd *abfd, const char *name); + +asection *bfd_get_section_by_name_if + (bfd *abfd, + const char *name, + bfd_boolean (*func) (bfd *abfd, asection *sect, void *obj), + void *obj); + +char *bfd_get_unique_section_name + (bfd *abfd, const char *templat, int *count); + +asection *bfd_make_section_old_way (bfd *abfd, const char *name); + +asection *bfd_make_section_anyway_with_flags + (bfd *abfd, const char *name, flagword flags); + +asection *bfd_make_section_anyway (bfd *abfd, const char *name); + +asection *bfd_make_section_with_flags + (bfd *, const char *name, flagword flags); + +asection *bfd_make_section (bfd *, const char *name); + +bfd_boolean bfd_set_section_flags + (bfd *abfd, asection *sec, flagword flags); + +void bfd_map_over_sections + (bfd *abfd, + void (*func) (bfd *abfd, asection *sect, void *obj), + void *obj); + +asection *bfd_sections_find_if + (bfd *abfd, + bfd_boolean (*operation) (bfd *abfd, asection *sect, void *obj), + void *obj); + +bfd_boolean bfd_set_section_size + (bfd *abfd, asection *sec, bfd_size_type val); + +bfd_boolean bfd_set_section_contents + (bfd *abfd, asection *section, const void *data, + file_ptr offset, bfd_size_type count); + +bfd_boolean bfd_get_section_contents + (bfd *abfd, asection *section, void *location, file_ptr offset, + bfd_size_type count); + +bfd_boolean bfd_malloc_and_get_section + (bfd *abfd, asection *section, bfd_byte **buf); + +bfd_boolean bfd_copy_private_section_data + (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)) +bfd_boolean bfd_generic_is_group_section (bfd *, const asection *sec); + +bfd_boolean bfd_generic_discard_group (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_mcf_isa_a_nodiv 9 +#define bfd_mach_mcf_isa_a 10 +#define bfd_mach_mcf_isa_a_mac 11 +#define bfd_mach_mcf_isa_a_emac 12 +#define bfd_mach_mcf_isa_aplus 13 +#define bfd_mach_mcf_isa_aplus_mac 14 +#define bfd_mach_mcf_isa_aplus_emac 15 +#define bfd_mach_mcf_isa_b_nousp 16 +#define bfd_mach_mcf_isa_b_nousp_mac 17 +#define bfd_mach_mcf_isa_b_nousp_emac 18 +#define bfd_mach_mcf_isa_b 19 +#define bfd_mach_mcf_isa_b_mac 20 +#define bfd_mach_mcf_isa_b_emac 21 +#define bfd_mach_mcf_isa_b_float 22 +#define bfd_mach_mcf_isa_b_float_mac 23 +#define bfd_mach_mcf_isa_b_float_emac 24 + 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_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) +/* Nonzero if MACH is a 64 bit sparc architecture. */ +#define bfd_mach_sparc_64bit_p(mach) \ + ((mach) >= bfd_mach_sparc_v9 && (mach) != bfd_mach_sparc_v8plusb) + 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_mips7000 7000 +#define bfd_mach_mips8000 8000 +#define bfd_mach_mips9000 9000 +#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 +#define bfd_mach_mipsisa64r2 65 + 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_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 +#define bfd_mach_h8300sx 6 +#define bfd_mach_h8300sxn 7 + 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 */ +#define bfd_mach_hppa10 10 +#define bfd_mach_hppa11 11 +#define bfd_mach_hppa20 20 +#define bfd_mach_hppa20w 25 + 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_sh2a 0x2a +#define bfd_mach_sh2a_nofpu 0x2b +#define bfd_mach_sh2a_nofpu_or_sh4_nommu_nofpu 0x2a1 +#define bfd_mach_sh2a_nofpu_or_sh3_nommu 0x2a2 +#define bfd_mach_sh2a_or_sh4 0x2a3 +#define bfd_mach_sh2a_or_sh3e 0x2a4 +#define bfd_mach_sh2e 0x2e +#define bfd_mach_sh3 0x30 +#define bfd_mach_sh3_nommu 0x31 +#define bfd_mach_sh3_dsp 0x3d +#define bfd_mach_sh3e 0x3e +#define bfd_mach_sh4 0x40 +#define bfd_mach_sh4_nofpu 0x41 +#define bfd_mach_sh4_nommu_nofpu 0x42 +#define bfd_mach_sh4a 0x4a +#define bfd_mach_sh4a_nofpu 0x4b +#define bfd_mach_sh4al_dsp 0x4d +#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' +#define bfd_mach_v850e1 '1' + 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_m32c, /* Renesas M16C/M32C. */ +#define bfd_mach_m16c 0x75 +#define bfd_mach_m32c 0x78 + bfd_arch_m32r, /* Renesas M32R (formerly Mitsubishi M32R/D) */ +#define bfd_mach_m32r 1 /* For backwards compatibility. */ +#define bfd_mach_m32rx 'x' +#define bfd_mach_m32r2 '2' + bfd_arch_mn10200, /* Matsushita MN10200 */ + bfd_arch_mn10300, /* Matsushita MN10300 */ +#define bfd_mach_mn10300 300 +#define bfd_mach_am33 330 +#define bfd_mach_am33_2 332 + 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_fr450 450 +#define bfd_mach_frvtomcat 499 /* fr500 prototype */ +#define bfd_mach_fr500 500 +#define bfd_mach_fr550 550 + 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_mt, +#define bfd_mach_ms1 1 +#define bfd_mach_mrisc2 2 +#define bfd_mach_ms2 3 + 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_bfin, /* ADI Blackfin */ +#define bfd_mach_bfin 1 + bfd_arch_cr16c, /* National Semiconductor CompactRISC. */ +#define bfd_mach_cr16c 1 + bfd_arch_crx, /* National Semiconductor CRX. */ +#define bfd_mach_crx 1 + bfd_arch_cris, /* Axis CRIS */ +#define bfd_mach_cris_v0_v10 255 +#define bfd_mach_cris_v32 32 +#define bfd_mach_cris_v10_v32 1032 + 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_msp11 11 +#define bfd_mach_msp110 110 +#define bfd_mach_msp12 12 +#define bfd_mach_msp13 13 +#define bfd_mach_msp14 14 +#define bfd_mach_msp15 15 +#define bfd_mach_msp16 16 +#define bfd_mach_msp21 21 +#define bfd_mach_msp31 31 +#define bfd_mach_msp32 32 +#define bfd_mach_msp33 33 +#define bfd_mach_msp41 41 +#define bfd_mach_msp42 42 +#define bfd_mach_msp43 43 +#define bfd_mach_msp44 44 + bfd_arch_xc16x, /* Infineon's XC16X Series. */ +#define bfd_mach_xc16x 1 +#define bfd_mach_xc16xl 2 +#define bfd_mach_xc16xs 3 + bfd_arch_xtensa, /* Tensilica's Xtensa cores. */ +#define bfd_mach_xtensa 1 + bfd_arch_maxq, /* Dallas MAXQ 10/20 */ +#define bfd_mach_maxq10 10 +#define bfd_mach_maxq20 20 + bfd_arch_z80, +#define bfd_mach_z80strict 1 /* No undocumented opcodes. */ +#define bfd_mach_z80 3 /* With ixl, ixh, iyl, and iyh. */ +#define bfd_mach_z80full 7 /* All undocumented instructions. */ +#define bfd_mach_r800 11 /* R800: successor with multiplication. */ + 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) + (const struct bfd_arch_info *a, const struct bfd_arch_info *b); + + bfd_boolean (*scan) (const struct bfd_arch_info *, const char *); + + const struct bfd_arch_info *next; +} +bfd_arch_info_type; + +const char *bfd_printable_name (bfd *abfd); + +const bfd_arch_info_type *bfd_scan_arch (const char *string); + +const char **bfd_arch_list (void); + +const bfd_arch_info_type *bfd_arch_get_compatible + (const bfd *abfd, const bfd *bbfd, bfd_boolean accept_unknowns); + +void bfd_set_arch_info (bfd *abfd, const bfd_arch_info_type *arg); + +enum bfd_architecture bfd_get_arch (bfd *abfd); + +unsigned long bfd_get_mach (bfd *abfd); + +unsigned int bfd_arch_bits_per_byte (bfd *abfd); + +unsigned int bfd_arch_bits_per_address (bfd *abfd); + +const bfd_arch_info_type *bfd_get_arch_info (bfd *abfd); + +const bfd_arch_info_type *bfd_lookup_arch + (enum bfd_architecture arch, unsigned long machine); + +const char *bfd_printable_arch_mach + (enum bfd_architecture arch, unsigned long machine); + +unsigned int bfd_octets_per_byte (bfd *abfd); + +unsigned int bfd_arch_mach_octets_per_byte + (enum bfd_architecture arch, unsigned long machine); + +/* Extracted from reloc.c. */ +typedef enum bfd_reloc_status +{ + /* No errors detected. */ + 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 bfd_symbol **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 value overflows when considered as a signed + number one bit larger than the field. ie. A bitfield of N bits + is allowed to represent -2**n to 2**n-1. */ + complain_overflow_bitfield, + + /* Complain if the value overflows when considered as a 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 accommodated (e.g., i960 callj + instructions). */ + bfd_reloc_status_type (*special_function) + (bfd *, arelent *, struct bfd_symbol *, void *, 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 != NULL) \ + { \ + if (bfd_is_com_section (symbol->section)) \ + { \ + relocation = 0; \ + } \ + else \ + { \ + relocation = symbol->value; \ + } \ + } \ + } + +unsigned int bfd_get_reloc_size (reloc_howto_type *); + +typedef struct relent_chain +{ + arelent relent; + struct relent_chain *next; +} +arelent_chain; + +bfd_reloc_status_type bfd_check_overflow + (enum complain_overflow how, + unsigned int bitsize, + unsigned int rightshift, + unsigned int addrsize, + bfd_vma relocation); + +bfd_reloc_status_type bfd_perform_relocation + (bfd *abfd, + arelent *reloc_entry, + void *data, + asection *input_section, + bfd *output_bfd, + char **error_message); + +bfd_reloc_status_type bfd_install_relocation + (bfd *abfd, + arelent *reloc_entry, + void *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, + +/* Section relative relocations. Some targets need this for DWARF2. */ + BFD_RELOC_32_SECREL, + +/* 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, + +/* High 16 bits of 32-bit pc-relative value */ + BFD_RELOC_HI16_PCREL, + +/* High 16 bits of 32-bit pc-relative value, adjusted */ + BFD_RELOC_HI16_S_PCREL, + +/* Low 16 bits of pc-relative value */ + BFD_RELOC_LO16_PCREL, + +/* MIPS16 high 16 bits of 32-bit value. */ + BFD_RELOC_MIPS16_HI16, + +/* MIPS16 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_MIPS16_HI16_S, + +/* MIPS16 low 16 bits. */ + BFD_RELOC_MIPS16_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, + BFD_RELOC_MIPS_TLS_DTPMOD32, + BFD_RELOC_MIPS_TLS_DTPREL32, + BFD_RELOC_MIPS_TLS_DTPMOD64, + BFD_RELOC_MIPS_TLS_DTPREL64, + BFD_RELOC_MIPS_TLS_GD, + BFD_RELOC_MIPS_TLS_LDM, + BFD_RELOC_MIPS_TLS_DTPREL_HI16, + BFD_RELOC_MIPS_TLS_DTPREL_LO16, + BFD_RELOC_MIPS_TLS_GOTTPREL, + BFD_RELOC_MIPS_TLS_TPREL32, + BFD_RELOC_MIPS_TLS_TPREL64, + BFD_RELOC_MIPS_TLS_TPREL_HI16, + BFD_RELOC_MIPS_TLS_TPREL_LO16, + + +/* MIPS ELF relocations (VxWorks extensions). */ + BFD_RELOC_MIPS_COPY, + BFD_RELOC_MIPS_JUMP_SLOT, + + +/* 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, + BFD_RELOC_FRV_GOT12, + BFD_RELOC_FRV_GOTHI, + BFD_RELOC_FRV_GOTLO, + BFD_RELOC_FRV_FUNCDESC, + BFD_RELOC_FRV_FUNCDESC_GOT12, + BFD_RELOC_FRV_FUNCDESC_GOTHI, + BFD_RELOC_FRV_FUNCDESC_GOTLO, + BFD_RELOC_FRV_FUNCDESC_VALUE, + BFD_RELOC_FRV_FUNCDESC_GOTOFF12, + BFD_RELOC_FRV_FUNCDESC_GOTOFFHI, + BFD_RELOC_FRV_FUNCDESC_GOTOFFLO, + BFD_RELOC_FRV_GOTOFF12, + BFD_RELOC_FRV_GOTOFFHI, + BFD_RELOC_FRV_GOTOFFLO, + BFD_RELOC_FRV_GETTLSOFF, + BFD_RELOC_FRV_TLSDESC_VALUE, + BFD_RELOC_FRV_GOTTLSDESC12, + BFD_RELOC_FRV_GOTTLSDESCHI, + BFD_RELOC_FRV_GOTTLSDESCLO, + BFD_RELOC_FRV_TLSMOFF12, + BFD_RELOC_FRV_TLSMOFFHI, + BFD_RELOC_FRV_TLSMOFFLO, + BFD_RELOC_FRV_GOTTLSOFF12, + BFD_RELOC_FRV_GOTTLSOFFHI, + BFD_RELOC_FRV_GOTTLSOFFLO, + BFD_RELOC_FRV_TLSOFF, + BFD_RELOC_FRV_TLSDESC_RELAX, + BFD_RELOC_FRV_GETTLSOFF_RELAX, + BFD_RELOC_FRV_TLSOFF_RELAX, + BFD_RELOC_FRV_TLSMOFF, + + +/* This is a 24bit GOT-relative reloc for the mn10300. */ + BFD_RELOC_MN10300_GOTOFF24, + +/* This is a 32bit GOT-relative reloc for the mn10300, offset by two bytes +in the instruction. */ + BFD_RELOC_MN10300_GOT32, + +/* This is a 24bit GOT-relative reloc for the mn10300, offset by two bytes +in the instruction. */ + BFD_RELOC_MN10300_GOT24, + +/* This is a 16bit GOT-relative reloc for the mn10300, offset by two bytes +in the instruction. */ + BFD_RELOC_MN10300_GOT16, + +/* Copy symbol at runtime. */ + BFD_RELOC_MN10300_COPY, + +/* Create GOT entry. */ + BFD_RELOC_MN10300_GLOB_DAT, + +/* Create PLT entry. */ + BFD_RELOC_MN10300_JMP_SLOT, + +/* Adjust by program base. */ + BFD_RELOC_MN10300_RELATIVE, + + +/* 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, + BFD_RELOC_386_TLS_GOTDESC, + BFD_RELOC_386_TLS_DESC_CALL, + BFD_RELOC_386_TLS_DESC, + +/* 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, + BFD_RELOC_X86_64_GOTOFF64, + BFD_RELOC_X86_64_GOTPC32, + BFD_RELOC_X86_64_GOT64, + BFD_RELOC_X86_64_GOTPCREL64, + BFD_RELOC_X86_64_GOTPC64, + BFD_RELOC_X86_64_GOTPLT64, + BFD_RELOC_X86_64_PLTOFF64, + BFD_RELOC_X86_64_GOTPC32_TLSDESC, + BFD_RELOC_X86_64_TLSDESC_CALL, + BFD_RELOC_X86_64_TLSDESC, + +/* 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 constructor 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, + +/* ARM 26-bit pc-relative branch for an unconditional BL or BLX instruction. */ + BFD_RELOC_ARM_PCREL_CALL, + +/* ARM 26-bit pc-relative branch for B or conditional BL instruction. */ + BFD_RELOC_ARM_PCREL_JUMP, + +/* Thumb 7-, 9-, 12-, 20-, 23-, and 25-bit pc-relative branches. +The lowest bit must be zero and is not stored in the instruction. +Note that the corresponding ELF R_ARM_THM_JUMPnn constant has an +"nn" one smaller in all cases. Note further that BRANCH23 +corresponds to R_ARM_THM_CALL. */ + BFD_RELOC_THUMB_PCREL_BRANCH7, + BFD_RELOC_THUMB_PCREL_BRANCH9, + BFD_RELOC_THUMB_PCREL_BRANCH12, + BFD_RELOC_THUMB_PCREL_BRANCH20, + BFD_RELOC_THUMB_PCREL_BRANCH23, + BFD_RELOC_THUMB_PCREL_BRANCH25, + +/* 12-bit immediate offset, used in ARM-format ldr and str instructions. */ + BFD_RELOC_ARM_OFFSET_IMM, + +/* 5-bit immediate offset, used in Thumb-format ldr and str instructions. */ + BFD_RELOC_ARM_THUMB_OFFSET, + +/* Pc-relative or absolute relocation depending on target. Used for +entries in .init_array sections. */ + BFD_RELOC_ARM_TARGET1, + +/* Read-only segment base relative address. */ + BFD_RELOC_ARM_ROSEGREL32, + +/* Data segment base relative address. */ + BFD_RELOC_ARM_SBREL32, + +/* This reloc is used for references to RTTI data from exception handling +tables. The actual definition depends on the target. It may be a +pc-relative or some form of GOT-indirect relocation. */ + BFD_RELOC_ARM_TARGET2, + +/* 31-bit PC relative address. */ + BFD_RELOC_ARM_PREL31, + +/* Relocations for setting up GOTs and PLTs for shared libraries. */ + BFD_RELOC_ARM_JUMP_SLOT, + BFD_RELOC_ARM_GLOB_DAT, + BFD_RELOC_ARM_GOT32, + BFD_RELOC_ARM_PLT32, + BFD_RELOC_ARM_RELATIVE, + BFD_RELOC_ARM_GOTOFF, + BFD_RELOC_ARM_GOTPC, + +/* ARM thread-local storage relocations. */ + BFD_RELOC_ARM_TLS_GD32, + BFD_RELOC_ARM_TLS_LDO32, + BFD_RELOC_ARM_TLS_LDM32, + BFD_RELOC_ARM_TLS_DTPOFF32, + BFD_RELOC_ARM_TLS_DTPMOD32, + BFD_RELOC_ARM_TLS_TPOFF32, + BFD_RELOC_ARM_TLS_IE32, + BFD_RELOC_ARM_TLS_LE32, + +/* 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_T32_IMMEDIATE, + BFD_RELOC_ARM_T32_IMM12, + BFD_RELOC_ARM_T32_ADD_PC12, + BFD_RELOC_ARM_SHIFT_IMM, + BFD_RELOC_ARM_SMC, + BFD_RELOC_ARM_SWI, + BFD_RELOC_ARM_MULTI, + BFD_RELOC_ARM_CP_OFF_IMM, + BFD_RELOC_ARM_CP_OFF_IMM_S2, + BFD_RELOC_ARM_T32_CP_OFF_IMM, + BFD_RELOC_ARM_T32_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_T32_OFFSET_U8, + BFD_RELOC_ARM_T32_OFFSET_IMM, + BFD_RELOC_ARM_HWLITERAL, + BFD_RELOC_ARM_THUMB_ADD, + BFD_RELOC_ARM_THUMB_IMM, + BFD_RELOC_ARM_THUMB_SHIFT, + +/* Renesas / SuperH SH relocs. Not all of these appear in object files. */ + BFD_RELOC_SH_PCDISP8BY2, + BFD_RELOC_SH_PCDISP12BY2, + BFD_RELOC_SH_IMM3, + BFD_RELOC_SH_IMM3U, + BFD_RELOC_SH_DISP12, + BFD_RELOC_SH_DISP12BY2, + BFD_RELOC_SH_DISP12BY4, + BFD_RELOC_SH_DISP12BY8, + BFD_RELOC_SH_DISP20, + BFD_RELOC_SH_DISP20BY8, + 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, + +/* 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, + +/* ADI Blackfin 16 bit immediate absolute reloc. */ + BFD_RELOC_BFIN_16_IMM, + +/* ADI Blackfin 16 bit immediate absolute reloc higher 16 bits. */ + BFD_RELOC_BFIN_16_HIGH, + +/* ADI Blackfin 'a' part of LSETUP. */ + BFD_RELOC_BFIN_4_PCREL, + +/* ADI Blackfin. */ + BFD_RELOC_BFIN_5_PCREL, + +/* ADI Blackfin 16 bit immediate absolute reloc lower 16 bits. */ + BFD_RELOC_BFIN_16_LOW, + +/* ADI Blackfin. */ + BFD_RELOC_BFIN_10_PCREL, + +/* ADI Blackfin 'b' part of LSETUP. */ + BFD_RELOC_BFIN_11_PCREL, + +/* ADI Blackfin. */ + BFD_RELOC_BFIN_12_PCREL_JUMP, + +/* ADI Blackfin Short jump, pcrel. */ + BFD_RELOC_BFIN_12_PCREL_JUMP_S, + +/* ADI Blackfin Call.x not implemented. */ + BFD_RELOC_BFIN_24_PCREL_CALL_X, + +/* ADI Blackfin Long Jump pcrel. */ + BFD_RELOC_BFIN_24_PCREL_JUMP_L, + +/* ADI Blackfin FD-PIC relocations. */ + BFD_RELOC_BFIN_GOT17M4, + BFD_RELOC_BFIN_GOTHI, + BFD_RELOC_BFIN_GOTLO, + BFD_RELOC_BFIN_FUNCDESC, + BFD_RELOC_BFIN_FUNCDESC_GOT17M4, + BFD_RELOC_BFIN_FUNCDESC_GOTHI, + BFD_RELOC_BFIN_FUNCDESC_GOTLO, + BFD_RELOC_BFIN_FUNCDESC_VALUE, + BFD_RELOC_BFIN_FUNCDESC_GOTOFF17M4, + BFD_RELOC_BFIN_FUNCDESC_GOTOFFHI, + BFD_RELOC_BFIN_FUNCDESC_GOTOFFLO, + BFD_RELOC_BFIN_GOTOFF17M4, + BFD_RELOC_BFIN_GOTOFFHI, + BFD_RELOC_BFIN_GOTOFFLO, + +/* ADI Blackfin GOT relocation. */ + BFD_RELOC_BFIN_GOT, + +/* ADI Blackfin PLTPC relocation. */ + BFD_RELOC_BFIN_PLTPC, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_PUSH, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_CONST, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_ADD, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_SUB, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_MULT, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_DIV, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_MOD, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_LSHIFT, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_RSHIFT, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_AND, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_OR, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_XOR, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_LAND, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_LOR, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_LEN, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_NEG, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_COMP, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_PAGE, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_HWPAGE, + +/* ADI Blackfin arithmetic relocation. */ + BFD_ARELOC_BFIN_ADDR, + +/* 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 M16C/M32C Relocations. */ + BFD_RELOC_M32C_HI8, + BFD_RELOC_M32C_RL_JUMP, + BFD_RELOC_M32C_RL_1ADDR, + BFD_RELOC_M32C_RL_2ADDR, + +/* 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, + +/* For PIC. */ + BFD_RELOC_M32R_GOT24, + BFD_RELOC_M32R_26_PLTREL, + BFD_RELOC_M32R_COPY, + BFD_RELOC_M32R_GLOB_DAT, + BFD_RELOC_M32R_JMP_SLOT, + BFD_RELOC_M32R_RELATIVE, + BFD_RELOC_M32R_GOTOFF, + BFD_RELOC_M32R_GOTOFF_HI_ULO, + BFD_RELOC_M32R_GOTOFF_HI_SLO, + BFD_RELOC_M32R_GOTOFF_LO, + BFD_RELOC_M32R_GOTPC24, + BFD_RELOC_M32R_GOT16_HI_ULO, + BFD_RELOC_M32R_GOT16_HI_SLO, + BFD_RELOC_M32R_GOT16_LO, + BFD_RELOC_M32R_GOTPC_HI_ULO, + BFD_RELOC_M32R_GOTPC_HI_SLO, + BFD_RELOC_M32R_GOTPC_LO, + +/* 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-contiguously 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-contiguously 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 variation of BFD_RELOC_LO16 that can be used in v850e ld.bu +instructions. */ + BFD_RELOC_V850_LO16_SPLIT_OFFSET, + +/* 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, + BFD_RELOC_MMIX_PUSHJ_STUBBABLE, + +/* 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 8 bit value (most high 8 bit +of 32 bit value) into 8 bit immediate value of LDI insn. */ + BFD_RELOC_AVR_MS8_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 negated 8 bit value (msb +of 32 bit value) into 8 bit immediate value of LDI insn. */ + BFD_RELOC_AVR_MS8_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, + +/* This is a 16 bit reloc for the AVR that stores all needed bits +for absolute addressing with ldi with overflow check to linktime */ + BFD_RELOC_AVR_LDI, + +/* This is a 6 bit reloc for the AVR that stores offset for ldd/std +instructions */ + BFD_RELOC_AVR_6, + +/* This is a 6 bit reloc for the AVR that stores offset for adiw/sbiw +instructions */ + BFD_RELOC_AVR_6_ADIW, + +/* 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, + +/* Long displacement extension. */ + BFD_RELOC_390_20, + BFD_RELOC_390_GOT20, + BFD_RELOC_390_GOTPLT20, + BFD_RELOC_390_TLS_GOTIE20, + +/* 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 inheritance 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 branches 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, + +/* Motorola 68HC12 reloc. +This is the 5 bits of a value. */ + BFD_RELOC_M68HC12_5B, + +/* NS CR16C Relocations. */ + BFD_RELOC_16C_NUM08, + BFD_RELOC_16C_NUM08_C, + BFD_RELOC_16C_NUM16, + BFD_RELOC_16C_NUM16_C, + BFD_RELOC_16C_NUM32, + BFD_RELOC_16C_NUM32_C, + BFD_RELOC_16C_DISP04, + BFD_RELOC_16C_DISP04_C, + BFD_RELOC_16C_DISP08, + BFD_RELOC_16C_DISP08_C, + BFD_RELOC_16C_DISP16, + BFD_RELOC_16C_DISP16_C, + BFD_RELOC_16C_DISP24, + BFD_RELOC_16C_DISP24_C, + BFD_RELOC_16C_DISP24a, + BFD_RELOC_16C_DISP24a_C, + BFD_RELOC_16C_REG04, + BFD_RELOC_16C_REG04_C, + BFD_RELOC_16C_REG04a, + BFD_RELOC_16C_REG04a_C, + BFD_RELOC_16C_REG14, + BFD_RELOC_16C_REG14_C, + BFD_RELOC_16C_REG16, + BFD_RELOC_16C_REG16_C, + BFD_RELOC_16C_REG20, + BFD_RELOC_16C_REG20_C, + BFD_RELOC_16C_ABS20, + BFD_RELOC_16C_ABS20_C, + BFD_RELOC_16C_ABS24, + BFD_RELOC_16C_ABS24_C, + BFD_RELOC_16C_IMM04, + BFD_RELOC_16C_IMM04_C, + BFD_RELOC_16C_IMM16, + BFD_RELOC_16C_IMM16_C, + BFD_RELOC_16C_IMM20, + BFD_RELOC_16C_IMM20_C, + BFD_RELOC_16C_IMM24, + BFD_RELOC_16C_IMM24_C, + BFD_RELOC_16C_IMM32, + BFD_RELOC_16C_IMM32_C, + +/* NS CRX Relocations. */ + BFD_RELOC_CRX_REL4, + BFD_RELOC_CRX_REL8, + BFD_RELOC_CRX_REL8_CMP, + BFD_RELOC_CRX_REL16, + BFD_RELOC_CRX_REL24, + BFD_RELOC_CRX_REL32, + BFD_RELOC_CRX_REGREL12, + BFD_RELOC_CRX_REGREL22, + BFD_RELOC_CRX_REGREL28, + BFD_RELOC_CRX_REGREL32, + BFD_RELOC_CRX_ABS16, + BFD_RELOC_CRX_ABS32, + BFD_RELOC_CRX_NUM8, + BFD_RELOC_CRX_NUM16, + BFD_RELOC_CRX_NUM32, + BFD_RELOC_CRX_IMM16, + BFD_RELOC_CRX_IMM32, + BFD_RELOC_CRX_SWITCH8, + BFD_RELOC_CRX_SWITCH16, + BFD_RELOC_CRX_SWITCH32, + +/* 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_SIGNED_8, + BFD_RELOC_CRIS_UNSIGNED_8, + BFD_RELOC_CRIS_SIGNED_16, + BFD_RELOC_CRIS_UNSIGNED_16, + BFD_RELOC_CRIS_LAPCQ_OFFSET, + 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, + +/* Infineon Relocations. */ + BFD_RELOC_XC16X_PAG, + BFD_RELOC_XC16X_POF, + BFD_RELOC_XC16X_SEG, + BFD_RELOC_XC16X_SOF, + +/* Relocations used by VAX ELF. */ + BFD_RELOC_VAX_GLOB_DAT, + BFD_RELOC_VAX_JMP_SLOT, + BFD_RELOC_VAX_RELATIVE, + +/* Morpho MT - 16 bit immediate relocation. */ + BFD_RELOC_MT_PC16, + +/* Morpho MT - Hi 16 bits of an address. */ + BFD_RELOC_MT_HI16, + +/* Morpho MT - Low 16 bits of an address. */ + BFD_RELOC_MT_LO16, + +/* Morpho MT - Used to tell the linker which vtable entries are used. */ + BFD_RELOC_MT_GNU_VTINHERIT, + +/* Morpho MT - Used to tell the linker which vtable entries are used. */ + BFD_RELOC_MT_GNU_VTENTRY, + +/* Morpho MT - 8 bit immediate relocation. */ + BFD_RELOC_MT_PCINSN8, + +/* 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, + BFD_RELOC_MSP430_2X_PCREL, + BFD_RELOC_MSP430_RL_PCREL, + +/* 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, + +/* Xtensa relocations to mark the difference of two local symbols. +These are only needed to support linker relaxation and can be ignored +when not relaxing. The field is set to the value of the difference +assuming no relaxation. The relocation encodes the position of the +first symbol so the linker can determine whether to adjust the field +value. */ + BFD_RELOC_XTENSA_DIFF8, + BFD_RELOC_XTENSA_DIFF16, + BFD_RELOC_XTENSA_DIFF32, + +/* Generic Xtensa relocations for instruction operands. Only the slot +number is encoded in the relocation. The relocation applies to the +last PC-relative immediate operand, or if there are no PC-relative +immediates, to the last immediate operand. */ + BFD_RELOC_XTENSA_SLOT0_OP, + BFD_RELOC_XTENSA_SLOT1_OP, + BFD_RELOC_XTENSA_SLOT2_OP, + BFD_RELOC_XTENSA_SLOT3_OP, + BFD_RELOC_XTENSA_SLOT4_OP, + BFD_RELOC_XTENSA_SLOT5_OP, + BFD_RELOC_XTENSA_SLOT6_OP, + BFD_RELOC_XTENSA_SLOT7_OP, + BFD_RELOC_XTENSA_SLOT8_OP, + BFD_RELOC_XTENSA_SLOT9_OP, + BFD_RELOC_XTENSA_SLOT10_OP, + BFD_RELOC_XTENSA_SLOT11_OP, + BFD_RELOC_XTENSA_SLOT12_OP, + BFD_RELOC_XTENSA_SLOT13_OP, + BFD_RELOC_XTENSA_SLOT14_OP, + +/* Alternate Xtensa relocations. Only the slot is encoded in the +relocation. The meaning of these relocations is opcode-specific. */ + BFD_RELOC_XTENSA_SLOT0_ALT, + BFD_RELOC_XTENSA_SLOT1_ALT, + BFD_RELOC_XTENSA_SLOT2_ALT, + BFD_RELOC_XTENSA_SLOT3_ALT, + BFD_RELOC_XTENSA_SLOT4_ALT, + BFD_RELOC_XTENSA_SLOT5_ALT, + BFD_RELOC_XTENSA_SLOT6_ALT, + BFD_RELOC_XTENSA_SLOT7_ALT, + BFD_RELOC_XTENSA_SLOT8_ALT, + BFD_RELOC_XTENSA_SLOT9_ALT, + BFD_RELOC_XTENSA_SLOT10_ALT, + BFD_RELOC_XTENSA_SLOT11_ALT, + BFD_RELOC_XTENSA_SLOT12_ALT, + BFD_RELOC_XTENSA_SLOT13_ALT, + BFD_RELOC_XTENSA_SLOT14_ALT, + +/* Xtensa relocations for backward compatibility. These have all been +replaced by BFD_RELOC_XTENSA_SLOT0_OP. */ + 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, + +/* 8 bit signed offset in (ix+d) or (iy+d). */ + BFD_RELOC_Z80_DISP8, + +/* DJNZ offset. */ + BFD_RELOC_Z8K_DISP7, + +/* CALR offset. */ + BFD_RELOC_Z8K_CALLR, + +/* 4 bit value. */ + BFD_RELOC_Z8K_IMM4L, + BFD_RELOC_UNUSED }; +typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; +reloc_howto_type *bfd_reloc_type_lookup + (bfd *abfd, bfd_reloc_code_real_type code); + +const char *bfd_get_reloc_code_name (bfd_reloc_code_real_type code); + +/* Extracted from syms.c. */ + +typedef struct bfd_symbol +{ + /* 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 arbitrary + 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 bfd_section *section; + + /* Back end special data. */ + union + { + void *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 (bfd *abfd, asymbol *sym); + +bfd_boolean bfd_is_local_label_name (bfd *abfd, const char *name); + +#define bfd_is_local_label_name(abfd, name) \ + BFD_SEND (abfd, _bfd_is_local_label_name, (abfd, name)) + +bfd_boolean bfd_is_target_special_symbol (bfd *abfd, asymbol *sym); + +#define bfd_is_target_special_symbol(abfd, sym) \ + BFD_SEND (abfd, _bfd_is_target_special_symbol, (abfd, sym)) + +#define bfd_canonicalize_symtab(abfd, location) \ + BFD_SEND (abfd, _bfd_canonicalize_symtab, (abfd, location)) + +bfd_boolean bfd_set_symtab + (bfd *abfd, asymbol **location, unsigned int count); + +void bfd_print_symbol_vandf (bfd *abfd, void *file, asymbol *symbol); + +#define bfd_make_empty_symbol(abfd) \ + BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) + +asymbol *_bfd_generic_make_empty_symbol (bfd *); + +#define bfd_make_debug_symbol(abfd,ptr,size) \ + BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) + +int bfd_decode_symclass (asymbol *symbol); + +bfd_boolean bfd_is_undefined_symclass (int symclass); + +void bfd_symbol_info (asymbol *symbol, symbol_info *ret); + +bfd_boolean bfd_copy_private_symbol_data + (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; + + /* The IOSTREAM, and corresponding IO vector that provide access + to the file backing the BFD. */ + void *iostream; + const struct bfd_iovec *iovec; + + /* 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 bfd_section *sections; + + /* The last section on the section list. */ + struct bfd_section *section_last; + + /* 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 bfd_symbol **outsymbols; + + /* Used for slurped dynamic symbol tables. */ + unsigned int dynsymcount; + + /* Pointer to structure which contains architecture information. */ + const struct bfd_arch_info *arch_info; + + /* Flag set if symbols from this BFD should not be exported. */ + bfd_boolean no_export; + + /* Stuff only useful for archives. */ + void *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; + void *any; + } + tdata; + + /* Used by the application to hold private data. */ + void *usrdata; + + /* Where all the allocated stuff under this BFD goes. This is a + struct objalloc *, but we use void * to avoid requiring the inclusion + of objalloc.h. */ + void *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 (void); + +void bfd_set_error (bfd_error_type error_tag); + +const char *bfd_errmsg (bfd_error_type error_tag); + +void bfd_perror (const char *message); + +typedef void (*bfd_error_handler_type) (const char *, ...); + +bfd_error_handler_type bfd_set_error_handler (bfd_error_handler_type); + +void bfd_set_error_program_name (const char *); + +bfd_error_handler_type bfd_get_error_handler (void); + +long bfd_get_reloc_upper_bound (bfd *abfd, asection *sect); + +long bfd_canonicalize_reloc + (bfd *abfd, asection *sec, arelent **loc, asymbol **syms); + +void bfd_set_reloc + (bfd *abfd, asection *sec, arelent **rel, unsigned int count); + +bfd_boolean bfd_set_file_flags (bfd *abfd, flagword flags); + +int bfd_get_arch_size (bfd *abfd); + +int bfd_get_sign_extend_vma (bfd *abfd); + +bfd_boolean bfd_set_start_address (bfd *abfd, bfd_vma vma); + +unsigned int bfd_get_gp_size (bfd *abfd); + +void bfd_set_gp_size (bfd *abfd, unsigned int i); + +bfd_vma bfd_scan_vma (const char *string, const char **end, int base); + +bfd_boolean bfd_copy_private_header_data (bfd *ibfd, bfd *obfd); + +#define bfd_copy_private_header_data(ibfd, obfd) \ + BFD_SEND (obfd, _bfd_copy_private_header_data, \ + (ibfd, obfd)) +bfd_boolean bfd_copy_private_bfd_data (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 (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 (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_find_line(abfd, syms, sym, file, line) \ + BFD_SEND (abfd, _bfd_find_line, \ + (abfd, syms, sym, file, line)) + +#define bfd_find_inliner_info(abfd, file, func, line) \ + BFD_SEND (abfd, _bfd_find_inliner_info, \ + (abfd, 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_is_group_section(abfd, sec) \ + BFD_SEND (abfd, _bfd_is_group_section, (abfd, sec)) + +#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(abfd, 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_synthetic_symtab(abfd, count, syms, dyncount, dynsyms, ret) \ + BFD_SEND (abfd, _bfd_get_synthetic_symtab, (abfd, count, syms, \ + dyncount, dynsyms, ret)) + +#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 + (bfd *, struct bfd_link_info *, struct bfd_link_order *, bfd_byte *, + bfd_boolean, asymbol **); + +bfd_boolean bfd_alt_mach_code (bfd *abfd, int alternative); + +struct bfd_preserve +{ + void *marker; + void *tdata; + flagword flags; + const struct bfd_arch_info *arch_info; + struct bfd_section *sections; + struct bfd_section *section_last; + unsigned int section_count; + struct bfd_hash_table section_htab; +}; + +bfd_boolean bfd_preserve_save (bfd *, struct bfd_preserve *); + +void bfd_preserve_restore (bfd *, struct bfd_preserve *); + +void bfd_preserve_finish (bfd *, struct bfd_preserve *); + +/* Extracted from archive.c. */ +symindex bfd_get_next_mapent + (bfd *abfd, symindex previous, carsym **sym); + +bfd_boolean bfd_set_archive_head (bfd *output, bfd *new_head); + +bfd *bfd_openr_next_archived_file (bfd *archive, bfd *previous); + +/* Extracted from corefile.c. */ +const char *bfd_core_file_failing_command (bfd *abfd); + +int bfd_core_file_failing_signal (bfd *abfd); + +bfd_boolean core_file_matches_executable_p + (bfd *core_bfd, bfd *exec_bfd); + +bfd_boolean generic_core_file_matches_executable_p + (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 as the first argument. + Certain other handlers could do the same. */ + bfd_uint64_t (*bfd_getx64) (const void *); + bfd_int64_t (*bfd_getx_signed_64) (const void *); + void (*bfd_putx64) (bfd_uint64_t, void *); + bfd_vma (*bfd_getx32) (const void *); + bfd_signed_vma (*bfd_getx_signed_32) (const void *); + void (*bfd_putx32) (bfd_vma, void *); + bfd_vma (*bfd_getx16) (const void *); + bfd_signed_vma (*bfd_getx_signed_16) (const void *); + void (*bfd_putx16) (bfd_vma, void *); + + /* Byte swapping for the headers. */ + bfd_uint64_t (*bfd_h_getx64) (const void *); + bfd_int64_t (*bfd_h_getx_signed_64) (const void *); + void (*bfd_h_putx64) (bfd_uint64_t, void *); + bfd_vma (*bfd_h_getx32) (const void *); + bfd_signed_vma (*bfd_h_getx_signed_32) (const void *); + void (*bfd_h_putx32) (bfd_vma, void *); + bfd_vma (*bfd_h_getx16) (const void *); + bfd_signed_vma (*bfd_h_getx_signed_16) (const void *); + void (*bfd_h_putx16) (bfd_vma, void *); + + /* 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]) (bfd *); + + /* Set the format of a file being written. */ + bfd_boolean (*_bfd_set_format[bfd_type_end]) (bfd *); + + /* Write cached information into a file being written, at <>. */ + bfd_boolean (*_bfd_write_contents[bfd_type_end]) (bfd *); + + + /* Generic entry points. */ +#define BFD_JUMP_TABLE_GENERIC(NAME) \ + NAME##_close_and_cleanup, \ + NAME##_bfd_free_cached_info, \ + NAME##_new_section_hook, \ + NAME##_get_section_contents, \ + NAME##_get_section_contents_in_window + + /* Called when the BFD is being closed to do any necessary cleanup. */ + bfd_boolean (*_close_and_cleanup) (bfd *); + /* Ask the BFD to free all cached information. */ + bfd_boolean (*_bfd_free_cached_info) (bfd *); + /* Called when a new section is created. */ + bfd_boolean (*_new_section_hook) (bfd *, sec_ptr); + /* Read the contents of a section. */ + bfd_boolean (*_bfd_get_section_contents) + (bfd *, sec_ptr, void *, file_ptr, bfd_size_type); + bfd_boolean (*_bfd_get_section_contents_in_window) + (bfd *, sec_ptr, bfd_window *, file_ptr, bfd_size_type); + + /* Entry points to copy private data. */ +#define BFD_JUMP_TABLE_COPY(NAME) \ + NAME##_bfd_copy_private_bfd_data, \ + NAME##_bfd_merge_private_bfd_data, \ + _bfd_generic_init_private_section_data, \ + NAME##_bfd_copy_private_section_data, \ + NAME##_bfd_copy_private_symbol_data, \ + NAME##_bfd_copy_private_header_data, \ + NAME##_bfd_set_private_flags, \ + 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) (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) (bfd *, bfd *); + /* Called to initialize BFD private section data from one object file + to another. */ +#define bfd_init_private_section_data(ibfd, isec, obfd, osec, link_info) \ + BFD_SEND (obfd, _bfd_init_private_section_data, (ibfd, isec, obfd, osec, link_info)) + bfd_boolean (*_bfd_init_private_section_data) + (bfd *, sec_ptr, bfd *, sec_ptr, struct bfd_link_info *); + /* Called to copy BFD private section data from one object file + to another. */ + bfd_boolean (*_bfd_copy_private_section_data) + (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) + (bfd *, asymbol *, bfd *, asymbol *); + /* Called to copy BFD private header data from one object file + to another. */ + bfd_boolean (*_bfd_copy_private_header_data) + (bfd *, bfd *); + /* Called to set private backend flags. */ + bfd_boolean (*_bfd_set_private_flags) (bfd *, flagword); + + /* Called to print private BFD data. */ + bfd_boolean (*_bfd_print_private_bfd_data) (bfd *, void *); + + /* Core file entry points. */ +#define BFD_JUMP_TABLE_CORE(NAME) \ + NAME##_core_file_failing_command, \ + NAME##_core_file_failing_signal, \ + NAME##_core_file_matches_executable_p + + char * (*_core_file_failing_command) (bfd *); + int (*_core_file_failing_signal) (bfd *); + bfd_boolean (*_core_file_matches_executable_p) (bfd *, bfd *); + + /* Archive entry points. */ +#define BFD_JUMP_TABLE_ARCHIVE(NAME) \ + NAME##_slurp_armap, \ + NAME##_slurp_extended_name_table, \ + NAME##_construct_extended_name_table, \ + NAME##_truncate_arname, \ + NAME##_write_armap, \ + NAME##_read_ar_hdr, \ + NAME##_openr_next_archived_file, \ + NAME##_get_elt_at_index, \ + NAME##_generic_stat_arch_elt, \ + NAME##_update_armap_timestamp + + bfd_boolean (*_bfd_slurp_armap) (bfd *); + bfd_boolean (*_bfd_slurp_extended_name_table) (bfd *); + bfd_boolean (*_bfd_construct_extended_name_table) + (bfd *, char **, bfd_size_type *, const char **); + void (*_bfd_truncate_arname) (bfd *, const char *, char *); + bfd_boolean (*write_armap) + (bfd *, unsigned int, struct orl *, unsigned int, int); + void * (*_bfd_read_ar_hdr_fn) (bfd *); + bfd * (*openr_next_archived_file) (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) (bfd *, symindex); + int (*_bfd_stat_arch_elt) (bfd *, struct stat *); + bfd_boolean (*_bfd_update_armap_timestamp) (bfd *); + + /* Entry points used for symbols. */ +#define BFD_JUMP_TABLE_SYMBOLS(NAME) \ + NAME##_get_symtab_upper_bound, \ + NAME##_canonicalize_symtab, \ + NAME##_make_empty_symbol, \ + NAME##_print_symbol, \ + NAME##_get_symbol_info, \ + NAME##_bfd_is_local_label_name, \ + NAME##_bfd_is_target_special_symbol, \ + NAME##_get_lineno, \ + NAME##_find_nearest_line, \ + _bfd_generic_find_line, \ + NAME##_find_inliner_info, \ + NAME##_bfd_make_debug_symbol, \ + NAME##_read_minisymbols, \ + NAME##_minisymbol_to_symbol + + long (*_bfd_get_symtab_upper_bound) (bfd *); + long (*_bfd_canonicalize_symtab) + (bfd *, struct bfd_symbol **); + struct bfd_symbol * + (*_bfd_make_empty_symbol) (bfd *); + void (*_bfd_print_symbol) + (bfd *, void *, struct bfd_symbol *, 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) + (bfd *, struct bfd_symbol *, 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) (bfd *, const char *); + bfd_boolean (*_bfd_is_target_special_symbol) (bfd *, asymbol *); + alent * (*_get_lineno) (bfd *, struct bfd_symbol *); + bfd_boolean (*_bfd_find_nearest_line) + (bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, + const char **, const char **, unsigned int *); + bfd_boolean (*_bfd_find_line) + (bfd *, struct bfd_symbol **, struct bfd_symbol *, + const char **, unsigned int *); + bfd_boolean (*_bfd_find_inliner_info) + (bfd *, 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) + (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) + (bfd *, bfd_boolean, void **, 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) + (bfd *, bfd_boolean, const void *, asymbol *); + + /* Routines for relocs. */ +#define BFD_JUMP_TABLE_RELOCS(NAME) \ + NAME##_get_reloc_upper_bound, \ + NAME##_canonicalize_reloc, \ + NAME##_bfd_reloc_type_lookup + + long (*_get_reloc_upper_bound) (bfd *, sec_ptr); + long (*_bfd_canonicalize_reloc) + (bfd *, sec_ptr, arelent **, struct bfd_symbol **); + /* See documentation on reloc types. */ + reloc_howto_type * + (*reloc_type_lookup) (bfd *, bfd_reloc_code_real_type); + + /* Routines used when writing an object file. */ +#define BFD_JUMP_TABLE_WRITE(NAME) \ + NAME##_set_arch_mach, \ + NAME##_set_section_contents + + bfd_boolean (*_bfd_set_arch_mach) + (bfd *, enum bfd_architecture, unsigned long); + bfd_boolean (*_bfd_set_section_contents) + (bfd *, sec_ptr, const void *, file_ptr, bfd_size_type); + + /* Routines used by the linker. */ +#define BFD_JUMP_TABLE_LINK(NAME) \ + NAME##_sizeof_headers, \ + NAME##_bfd_get_relocated_section_contents, \ + NAME##_bfd_relax_section, \ + NAME##_bfd_link_hash_table_create, \ + NAME##_bfd_link_hash_table_free, \ + NAME##_bfd_link_add_symbols, \ + NAME##_bfd_link_just_syms, \ + NAME##_bfd_final_link, \ + NAME##_bfd_link_split_section, \ + NAME##_bfd_gc_sections, \ + NAME##_bfd_merge_sections, \ + NAME##_bfd_is_group_section, \ + NAME##_bfd_discard_group, \ + NAME##_section_already_linked \ + + int (*_bfd_sizeof_headers) (bfd *, bfd_boolean); + bfd_byte * (*_bfd_get_relocated_section_contents) + (bfd *, struct bfd_link_info *, struct bfd_link_order *, + bfd_byte *, bfd_boolean, struct bfd_symbol **); + + bfd_boolean (*_bfd_relax_section) + (bfd *, struct bfd_section *, 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) (bfd *); + + /* Release the memory associated with the linker hash table. */ + void (*_bfd_link_hash_table_free) (struct bfd_link_hash_table *); + + /* Add symbols from this object file into the hash table. */ + bfd_boolean (*_bfd_link_add_symbols) (bfd *, struct bfd_link_info *); + + /* Indicate that we are only retrieving symbol values from this section. */ + void (*_bfd_link_just_syms) (asection *, struct bfd_link_info *); + + /* Do a link based on the link_order structures attached to each + section of the BFD. */ + bfd_boolean (*_bfd_final_link) (bfd *, struct bfd_link_info *); + + /* Should this section be split up into smaller pieces during linking. */ + bfd_boolean (*_bfd_link_split_section) (bfd *, struct bfd_section *); + + /* Remove sections that are not referenced from the output. */ + bfd_boolean (*_bfd_gc_sections) (bfd *, struct bfd_link_info *); + + /* Attempt to merge SEC_MERGE sections. */ + bfd_boolean (*_bfd_merge_sections) (bfd *, struct bfd_link_info *); + + /* Is this section a member of a group? */ + bfd_boolean (*_bfd_is_group_section) (bfd *, const struct bfd_section *); + + /* Discard members of a group. */ + bfd_boolean (*_bfd_discard_group) (bfd *, struct bfd_section *); + + /* Check if SEC has been already linked during a reloceatable or + final link. */ + void (*_section_already_linked) (bfd *, struct bfd_section *); + + /* Routines to handle dynamic symbols and relocs. */ +#define BFD_JUMP_TABLE_DYNAMIC(NAME) \ + NAME##_get_dynamic_symtab_upper_bound, \ + NAME##_canonicalize_dynamic_symtab, \ + NAME##_get_synthetic_symtab, \ + NAME##_get_dynamic_reloc_upper_bound, \ + NAME##_canonicalize_dynamic_reloc + + /* Get the amount of memory required to hold the dynamic symbols. */ + long (*_bfd_get_dynamic_symtab_upper_bound) (bfd *); + /* Read in the dynamic symbols. */ + long (*_bfd_canonicalize_dynamic_symtab) + (bfd *, struct bfd_symbol **); + /* Create synthetized symbols. */ + long (*_bfd_get_synthetic_symtab) + (bfd *, long, struct bfd_symbol **, long, struct bfd_symbol **, + struct bfd_symbol **); + /* Get the amount of memory required to hold the dynamic relocs. */ + long (*_bfd_get_dynamic_reloc_upper_bound) (bfd *); + /* Read in the dynamic relocs. */ + long (*_bfd_canonicalize_dynamic_reloc) + (bfd *, arelent **, struct bfd_symbol **); + + /* 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. */ + const void *backend_data; + +} bfd_target; + +bfd_boolean bfd_set_default_target (const char *name); + +const bfd_target *bfd_find_target (const char *target_name, bfd *abfd); + +const char ** bfd_target_list (void); + +const bfd_target *bfd_search_for_target + (int (*search_func) (const bfd_target *, void *), + void *); + +/* Extracted from format.c. */ +bfd_boolean bfd_check_format (bfd *abfd, bfd_format format); + +bfd_boolean bfd_check_format_matches + (bfd *abfd, bfd_format format, char ***matching); + +bfd_boolean bfd_set_format (bfd *abfd, bfd_format format); + +const char *bfd_format_string (bfd_format format); + +/* Extracted from linker.c. */ +bfd_boolean bfd_link_split_section (bfd *abfd, asection *sec); + +#define bfd_link_split_section(abfd, sec) \ + BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec)) + +void bfd_section_already_linked (bfd *abfd, asection *sec); + +#define bfd_section_already_linked(abfd, sec) \ + BFD_SEND (abfd, _section_already_linked, (abfd, sec)) + +/* Extracted from simple.c. */ +bfd_byte *bfd_simple_get_relocated_section_contents + (bfd *abfd, asection *sec, bfd_byte *outbuf, asymbol **symbol_table); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/contrib/binutils-2.17/bfd/bfd.c b/contrib/binutils-2.17/bfd/bfd.c new file mode 100644 index 0000000000..733f6ee027 --- /dev/null +++ b/contrib/binutils-2.17/bfd/bfd.c @@ -0,0 +1,1515 @@ +/* Generic BFD library interface and support routines. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004, 2005, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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; +. +. {* The IOSTREAM, and corresponding IO vector that provide access +. to the file backing the BFD. *} +. void *iostream; +. const struct bfd_iovec *iovec; +. +. {* 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 bfd_section *sections; +. +. {* The last section on the section list. *} +. struct bfd_section *section_last; +. +. {* 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 bfd_symbol **outsymbols; +. +. {* Used for slurped dynamic symbol tables. *} +. unsigned int dynsymcount; +. +. {* Pointer to structure which contains architecture information. *} +. const struct bfd_arch_info *arch_info; +. +. {* Flag set if symbols from this BFD should not be exported. *} +. bfd_boolean no_export; +. +. {* Stuff only useful for archives. *} +. void *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; +. void *any; +. } +. tdata; +. +. {* Used by the application to hold private data. *} +. void *usrdata; +. +. {* Where all the allocated stuff under this BFD goes. This is a +. struct objalloc *, but we use void * to avoid requiring the inclusion +. of objalloc.h. *} +. void *memory; +.}; +. +*/ + +#include "bfd.h" +#include "bfdver.h" +#include "sysdep.h" +#include +#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" + +#ifndef EXIT_FAILURE +#define EXIT_FAILURE 1 +#endif + + +/* 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 (void) +{ + 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 (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 (bfd_error_type error_tag) +{ +#ifndef errno + extern int errno; +#endif + if (error_tag == bfd_error_system_call) + return xstrerror (errno); + + if (error_tag > bfd_error_invalid_error_code) + error_tag = bfd_error_invalid_error_code; /* sanity check */ + + return _(bfd_errmsgs [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 (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 overridden by the program. + + The BFD error handler acts like printf. + +CODE_FRAGMENT +. +.typedef void (*bfd_error_handler_type) (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. + Like fprintf (stderr, ...), but also handles some extra format specifiers. + + %A section name from section. For group components, print group name too. + %B file name from bfd. For archive components, prints archive too. + */ + +void +_bfd_default_error_handler (const char *fmt, ...) +{ + va_list ap; + char *bufp; + const char *new_fmt, *p; + size_t avail = 1000; + char buf[1000]; + + if (_bfd_error_program_name != NULL) + fprintf (stderr, "%s: ", _bfd_error_program_name); + else + fprintf (stderr, "BFD: "); + + va_start (ap, fmt); + new_fmt = fmt; + bufp = buf; + + /* Reserve enough space for the existing format string. */ + avail -= strlen (fmt) + 1; + if (avail > 1000) + _exit (EXIT_FAILURE); + + p = fmt; + while (1) + { + char *q; + size_t len, extra, trim; + + p = strchr (p, '%'); + if (p == NULL || p[1] == '\0') + { + if (new_fmt == buf) + { + len = strlen (fmt); + memcpy (bufp, fmt, len + 1); + } + break; + } + + if (p[1] == 'A' || p[1] == 'B') + { + len = p - fmt; + memcpy (bufp, fmt, len); + bufp += len; + fmt = p + 2; + new_fmt = buf; + + /* If we run out of space, tough, you lose your ridiculously + long file or section name. It's not safe to try to alloc + memory here; We might be printing an out of memory message. */ + if (avail == 0) + { + *bufp++ = '*'; + *bufp++ = '*'; + *bufp = '\0'; + } + else + { + if (p[1] == 'B') + { + bfd *abfd = va_arg (ap, bfd *); + if (abfd->my_archive) + snprintf (bufp, avail, "%s(%s)", + abfd->my_archive->filename, abfd->filename); + else + snprintf (bufp, avail, "%s", abfd->filename); + } + else + { + asection *sec = va_arg (ap, asection *); + bfd *abfd = sec->owner; + const char *group = NULL; + struct coff_comdat_info *ci; + + if (abfd != NULL + && bfd_get_flavour (abfd) == bfd_target_elf_flavour + && elf_next_in_group (sec) != NULL + && (sec->flags & SEC_GROUP) == 0) + group = elf_group_name (sec); + else if (abfd != NULL + && bfd_get_flavour (abfd) == bfd_target_coff_flavour + && (ci = bfd_coff_get_comdat_section (sec->owner, + sec)) != NULL) + group = ci->name; + if (group != NULL) + snprintf (bufp, avail, "%s[%s]", sec->name, group); + else + snprintf (bufp, avail, "%s", sec->name); + } + len = strlen (bufp); + avail = avail - len + 2; + + /* We need to replace any '%' we printed by "%%". + First count how many. */ + q = bufp; + bufp += len; + extra = 0; + while ((q = strchr (q, '%')) != NULL) + { + ++q; + ++extra; + } + + /* If there isn't room, trim off the end of the string. */ + q = bufp; + bufp += extra; + if (extra > avail) + { + trim = extra - avail; + bufp -= trim; + do + { + if (*--q == '%') + --extra; + } + while (--trim != 0); + *q = '\0'; + avail = extra; + } + avail -= extra; + + /* Now double all '%' chars, shuffling the string as we go. */ + while (extra != 0) + { + while ((q[extra] = *q) != '%') + --q; + q[--extra] = '%'; + --q; + } + } + } + p = p + 2; + } + + vfprintf (stderr, new_fmt, ap); + va_end (ap); + + putc ('\n', stderr); +} + +/* 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 (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 (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 (void) +{ + return _bfd_error_handler; +} + +/* +SECTION + Miscellaneous + +SUBSECTION + Miscellaneous functions +*/ + +/* +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 (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 (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 (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 (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 (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. */ + +void +_bfd_abort (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")); + _exit (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 (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 (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 & PE COFF (x86 COFF variants). + 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 + || strcmp (name, "pe-i386") == 0 + || strcmp (name, "pei-i386") == 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 (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 (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 (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 (bfd *abfd) +{ + if (! abfd) + return 0; + 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 (bfd *abfd, bfd_vma v) +{ + if (! abfd) + BFD_FAIL (); + 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 (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 strtoul (string, (char **) end, base); + +#ifdef HAVE_STRTOULL + if (sizeof (bfd_vma) <= sizeof (unsigned long long)) + return strtoull (string, (char **) end, base); +#endif + + 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_header_data + +SYNOPSIS + bfd_boolean bfd_copy_private_header_data (bfd *ibfd, bfd *obfd); + +DESCRIPTION + Copy private BFD header information from the BFD @var{ibfd} to the + the BFD @var{obfd}. This copies information that may require + sections to exist, but does not require symbol tables. 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_header_data(ibfd, obfd) \ +. BFD_SEND (obfd, _bfd_copy_private_header_data, \ +. (ibfd, obfd)) + +*/ + +/* +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_find_line(abfd, syms, sym, file, line) \ +. BFD_SEND (abfd, _bfd_find_line, \ +. (abfd, syms, sym, file, line)) +. +.#define bfd_find_inliner_info(abfd, file, func, line) \ +. BFD_SEND (abfd, _bfd_find_inliner_info, \ +. (abfd, 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_is_group_section(abfd, sec) \ +. BFD_SEND (abfd, _bfd_is_group_section, (abfd, sec)) +. +.#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(abfd, 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_synthetic_symtab(abfd, count, syms, dyncount, dynsyms, ret) \ +. BFD_SEND (abfd, _bfd_get_synthetic_symtab, (abfd, count, syms, \ +. dyncount, dynsyms, ret)) +. +.#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 +. (bfd *, struct bfd_link_info *, struct bfd_link_order *, bfd_byte *, +. bfd_boolean, asymbol **); +. + +*/ + +bfd_byte * +bfd_get_relocated_section_contents (bfd *abfd, + struct bfd_link_info *link_info, + struct bfd_link_order *link_order, + bfd_byte *data, + bfd_boolean relocatable, + asymbol **symbols) +{ + bfd *abfd2; + bfd_byte *(*fn) (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, relocatable, symbols); +} + +/* Record information about an ELF program header. */ + +bfd_boolean +bfd_record_phdr (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 = 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 = flags_valid; + m->p_paddr_valid = at_valid; + m->includes_filehdr = includes_filehdr; + m->includes_phdrs = 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 (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 (bfd *abfd, void *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 (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 +.{ +. void *marker; +. void *tdata; +. flagword flags; +. const struct bfd_arch_info *arch_info; +. struct bfd_section *sections; +. struct bfd_section *section_last; +. 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 (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_last = abfd->section_last; + preserve->section_count = abfd->section_count; + preserve->section_htab = abfd->section_htab; + + if (! bfd_hash_table_init (&abfd->section_htab, bfd_section_hash_newfunc, + sizeof (struct section_hash_entry))) + return FALSE; + + abfd->tdata.any = NULL; + abfd->arch_info = &bfd_default_arch_struct; + abfd->flags &= BFD_IN_MEMORY; + abfd->sections = NULL; + abfd->section_last = NULL; + 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 (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_last = preserve->section_last; + 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 (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.17/bfd/bfdio.c b/contrib/binutils-2.17/bfd/bfdio.c new file mode 100644 index 0000000000..22ea886b5c --- /dev/null +++ b/contrib/binutils-2.17/bfd/bfdio.c @@ -0,0 +1,447 @@ +/* Low-level I/O routines for BFDs. + + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 + +file_ptr +real_ftell (FILE *file) +{ +#if defined (HAVE_FTELLO64) + return ftello64 (file); +#elif defined (HAVE_FTELLO) + return ftello (file); +#else + return ftell (file); +#endif +} + +int +real_fseek (FILE *file, file_ptr offset, int whence) +{ +#if defined (HAVE_FSEEKO64) + return fseeko64 (file, offset, whence); +#elif defined (HAVE_FSEEKO) + return fseeko (file, offset, whence); +#else + return fseek (file, offset, whence); +#endif +} + +FILE * +real_fopen (const char *filename, const char *modes) +{ +#if defined (HAVE_FOPEN64) + return fopen64 (filename, modes); +#else + return fopen (filename, modes); +#endif +} + +/* +INTERNAL_DEFINITION + struct bfd_iovec + +DESCRIPTION + + The <> contains the internal file I/O class. + Each <> has an instance of this class and all file I/O is + routed through it (it is assumed that the instance implements + all methods listed below). + +.struct bfd_iovec +.{ +. {* To avoid problems with macros, a "b" rather than "f" +. prefix is prepended to each method name. *} +. {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching +. bytes starting at PTR. Return the number of bytes actually +. transfered (a read past end-of-file returns less than NBYTES), +. or -1 (setting <>) if an error occurs. *} +. file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes); +. file_ptr (*bwrite) (struct bfd *abfd, const void *ptr, +. file_ptr nbytes); +. {* Return the current IOSTREAM file offset, or -1 (setting <> +. if an error occurs. *} +. file_ptr (*btell) (struct bfd *abfd); +. {* For the following, on successful completion a value of 0 is returned. +. Otherwise, a value of -1 is returned (and <> is set). *} +. int (*bseek) (struct bfd *abfd, file_ptr offset, int whence); +. int (*bclose) (struct bfd *abfd); +. int (*bflush) (struct bfd *abfd); +. int (*bstat) (struct bfd *abfd, struct stat *sb); +.}; + +*/ + + +/* Return value is amount read. */ + +bfd_size_type +bfd_bread (void *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 = 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; + } + + if (abfd->iovec) + nread = abfd->iovec->bread (abfd, ptr, size); + else + nread = 0; + if (nread != (size_t) -1) + abfd->where += nread; + + return nread; +} + +bfd_size_type +bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd) +{ + size_t nwrote; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + { + struct bfd_in_memory *bim = 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_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; + } + + if (abfd->iovec) + nwrote = abfd->iovec->bwrite (abfd, ptr, size); + else + nwrote = 0; + + 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; +} + +file_ptr +bfd_tell (bfd *abfd) +{ + file_ptr ptr; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + return abfd->where; + + if (abfd->iovec) + { + ptr = abfd->iovec->btell (abfd); + + if (abfd->my_archive) + ptr -= abfd->origin; + } + else + ptr = 0; + + abfd->where = ptr; + return ptr; +} + +int +bfd_flush (bfd *abfd) +{ + if ((abfd->flags & BFD_IN_MEMORY) != 0) + return 0; + + if (abfd->iovec) + return abfd->iovec->bflush (abfd); + return 0; +} + +/* Returns 0 for success, negative value for failure (in which case + bfd_get_error can retrieve the error code). */ +int +bfd_stat (bfd *abfd, struct stat *statbuf) +{ + int result; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + abort (); + + if (abfd->iovec) + result = abfd->iovec->bstat (abfd, statbuf); + else + result = -1; + + 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 (bfd *abfd, file_ptr position, int direction) +{ + int result; + file_ptr 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 = 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_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 (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. */ + } + + file_position = position; + if (direction == SEEK_SET && abfd->my_archive != NULL) + file_position += abfd->origin; + + if (abfd->iovec) + result = abfd->iovec->bseek (abfd, file_position, direction); + else + result = -1; + + 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 (bfd *abfd) +{ + struct stat buf; + + if (abfd->mtime_set) + return abfd->mtime; + + if (abfd->iovec == NULL) + return 0; + + if (abfd->iovec->bstat (abfd, &buf) != 0) + 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 question, "is the + size reasonable?". +*/ + +long +bfd_get_size (bfd *abfd) +{ + struct stat buf; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + return ((struct bfd_in_memory *) abfd->iostream)->size; + + if (abfd->iovec == NULL) + return 0; + + if (abfd->iovec->bstat (abfd, &buf) != 0) + return 0; + + return buf.st_size; +} diff --git a/contrib/binutils-2.17/bfd/binary.c b/contrib/binutils-2.17/bfd/binary.c new file mode 100644 index 0000000000..458626f02a --- /dev/null +++ b/contrib/binutils-2.17/bfd/binary.c @@ -0,0 +1,378 @@ +/* BFD back-end for binary objects. + Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 + +/* Set by external programs - specifies the BFD architecture and + machine number to be uses when creating binary BFDs. */ +enum bfd_architecture bfd_external_binary_architecture = bfd_arch_unknown; +unsigned long bfd_external_machine = 0; + +/* Create a binary object. Invoked via bfd_set_format. */ + +static bfd_boolean +binary_mkobject (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 (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->size = statbuf.st_size; + sec->filepos = 0; + + abfd->tdata.any = (void *) 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, bfd_external_machine)); + } + + 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 (bfd *abfd, + asection *section ATTRIBUTE_UNUSED, + void * 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 (bfd *abfd ATTRIBUTE_UNUSED) +{ + return (BIN_SYMS + 1) * sizeof (asymbol *); +} + +/* Create a symbol name based on the bfd's filename. */ + +static char * +mangle_name (bfd *abfd, char *suffix) +{ + bfd_size_type size; + char *buf; + char *p; + + size = (strlen (bfd_get_filename (abfd)) + + strlen (suffix) + + sizeof "_binary__"); + + buf = 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_canonicalize_symtab (bfd *abfd, asymbol **alocation) +{ + asection *sec = (asection *) abfd->tdata.any; + asymbol *syms; + unsigned int i; + bfd_size_type amt = BIN_SYMS * sizeof (asymbol); + + syms = 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->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->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 (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_find_inliner_info _bfd_nosymbols_find_inliner_info +#define binary_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define binary_read_minisymbols _bfd_generic_read_minisymbols +#define binary_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol +#define binary_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup +#define binary_get_reloc_upper_bound ((long (*) (bfd *, asection *)) bfd_0l) +#define binary_canonicalize_reloc ((long (*) (bfd *, asection *, arelent **, asymbol **)) bfd_0l) +#define binary_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) + +/* 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 (bfd *abfd, + asection *sec, + const void * 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->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->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 (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_is_group_section bfd_generic_is_group_section +#define binary_bfd_discard_group bfd_generic_discard_group +#define binary_section_already_linked _bfd_generic_section_already_linked +#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_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.17/bfd/cache.c b/contrib/binutils-2.17/bfd/cache.c new file mode 100644 index 0000000000..6db6a6b4d5 --- /dev/null +++ b/contrib/binutils-2.17/bfd/cache.c @@ -0,0 +1,532 @@ +/* BFD library -- caching of file descriptors. + + Copyright 1990, 1991, 1992, 1993, 1994, 1996, 2000, 2001, 2002, + 2003, 2004, 2005 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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. + +SUBSECTION + Caching functions +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libiberty.h" + +/* In some cases we can optimize cache operation when reopening files. + For instance, a flush is entirely unnecessary if the file is already + closed, so a flush would use CACHE_NO_OPEN. Similarly, a seek using + SEEK_SET or SEEK_END need not first seek to the current position. + For stat we ignore seek errors, just in case the file has changed + while we weren't looking. If it has, then it's possible that the + file is shorter and we don't want a seek error to prevent us doing + the stat. */ +enum cache_flag { + CACHE_NORMAL = 0, + CACHE_NO_OPEN = 1, + CACHE_NO_SEEK = 2, + CACHE_NO_SEEK_ERROR = 4 +}; + +/* 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; + +/* 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. */ + +static bfd *bfd_last_cache = NULL; + +/* Insert a BFD into the cache. */ + +static void +insert (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 void +snip (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; + } +} + +/* Close a BFD and remove it from the cache. */ + +static bfd_boolean +bfd_cache_delete (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; +} + +/* 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 (void) +{ + 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 = real_ftell ((FILE *) kill->iostream); + + /* Save the file st_mtime. This is a hack so that gdb can detect when + an executable has been deleted and recreated. The only thing that + makes this reasonable is that st_mtime doesn't change when a file + is unlinked, so saving st_mtime makes BFD's file cache operation + a little more transparent for this particular usage pattern. If we + hadn't closed the file then we would not have lost the original + contents, st_mtime etc. Of course, if something is writing to an + existing file, then this is the wrong thing to do. + FIXME: gdb should save these times itself on first opening a file, + and this hack be removed. */ + if (kill->direction == no_direction || kill->direction == read_direction) + { + bfd_get_mtime (kill); + kill->mtime_set = TRUE; + } + + return bfd_cache_delete (kill); +} + +/* 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, flag) \ + ((x) == bfd_last_cache \ + ? (FILE *) (bfd_last_cache->iostream) \ + : bfd_cache_lookup_worker (x, flag)) + +/* 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. It will return NULL + if it is unable to (re)open the @var{abfd}. */ + +static FILE * +bfd_cache_lookup_worker (bfd *abfd, enum cache_flag flag) +{ + bfd *orig_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); + } + return (FILE *) abfd->iostream; + } + + if (flag & CACHE_NO_OPEN) + return NULL; + + if (bfd_open_file (abfd) == NULL) + ; + else if (!(flag & CACHE_NO_SEEK) + && real_fseek ((FILE *) abfd->iostream, abfd->where, SEEK_SET) != 0 + && !(flag & CACHE_NO_SEEK_ERROR)) + bfd_set_error (bfd_error_system_call); + else + return (FILE *) abfd->iostream; + + (*_bfd_error_handler) (_("reopening %B: %s\n"), + orig_bfd, bfd_errmsg (bfd_get_error ())); + return NULL; +} + +static file_ptr +cache_btell (struct bfd *abfd) +{ + FILE *f = bfd_cache_lookup (abfd, CACHE_NO_OPEN); + if (f == NULL) + return abfd->where; + return real_ftell (f); +} + +static int +cache_bseek (struct bfd *abfd, file_ptr offset, int whence) +{ + FILE *f = bfd_cache_lookup (abfd, whence != SEEK_CUR ? CACHE_NO_SEEK : 0); + if (f == NULL) + return -1; + return real_fseek (f, offset, whence); +} + +/* 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 file_ptr +cache_bread (struct bfd *abfd, void *buf, file_ptr nbytes) +{ + FILE *f; + file_ptr nread; + /* 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 (nbytes == 0) + return 0; + + f = bfd_cache_lookup (abfd, 0); + if (f == NULL) + return 0; + +#if defined (__VAX) && defined (VMS) + /* Apparently fread on Vax VMS does not keep the record length + information. */ + nread = read (fileno (f), buf, nbytes); + /* 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. */ + if (nread == (file_ptr)-1) + { + bfd_set_error (bfd_error_system_call); + return -1; + } +#else + nread = fread (buf, 1, nbytes, f); + /* 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. */ + if (nread < nbytes && ferror (f)) + { + bfd_set_error (bfd_error_system_call); + return -1; + } +#endif + return nread; +} + +static file_ptr +cache_bwrite (struct bfd *abfd, const void *where, file_ptr nbytes) +{ + file_ptr nwrite; + FILE *f = bfd_cache_lookup (abfd, 0); + if (f == NULL) + return 0; + nwrite = fwrite (where, 1, nbytes, f); + if (nwrite < nbytes && ferror (f)) + { + bfd_set_error (bfd_error_system_call); + return -1; + } + return nwrite; +} + +static int +cache_bclose (struct bfd *abfd) +{ + return bfd_cache_close (abfd); +} + +static int +cache_bflush (struct bfd *abfd) +{ + int sts; + FILE *f = bfd_cache_lookup (abfd, CACHE_NO_OPEN); + if (f == NULL) + return 0; + sts = fflush (f); + if (sts < 0) + bfd_set_error (bfd_error_system_call); + return sts; +} + +static int +cache_bstat (struct bfd *abfd, struct stat *sb) +{ + int sts; + FILE *f = bfd_cache_lookup (abfd, CACHE_NO_SEEK_ERROR); + if (f == NULL) + return -1; + sts = fstat (fileno (f), sb); + if (sts < 0) + bfd_set_error (bfd_error_system_call); + return sts; +} + +static const struct bfd_iovec cache_iovec = { + &cache_bread, &cache_bwrite, &cache_btell, &cache_bseek, + &cache_bclose, &cache_bflush, &cache_bstat +}; + +/* +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 (bfd *abfd) +{ + BFD_ASSERT (abfd->iostream != NULL); + if (open_files >= BFD_CACHE_MAX_OPEN) + { + if (! close_one ()) + return FALSE; + } + abfd->iovec = &cache_iovec; + 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 (bfd *abfd) +{ + if (abfd->iovec != &cache_iovec) + return TRUE; + + if (abfd->iostream == NULL) + /* Previously closed. */ + return TRUE; + + return bfd_cache_delete (abfd); +} + +/* +FUNCTION + bfd_cache_close_all + +SYNOPSIS + bfd_boolean bfd_cache_close_all (void); + +DESCRIPTION + Remove all BFDs from the cache. If the attached file is open, + then close it too. + +RETURNS + <> is returned if closing one of the file fails, <> is + returned if all is well. +*/ + +bfd_boolean +bfd_cache_close_all () +{ + bfd_boolean ret = TRUE; + + while (bfd_last_cache != NULL) + ret &= bfd_cache_close (bfd_last_cache); + + return ret; +} + +/* +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 (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) real_fopen (abfd->filename, FOPEN_RB); + break; + case both_direction: + case write_direction: + if (abfd->opened_once) + { + abfd->iostream = (PTR) real_fopen (abfd->filename, FOPEN_RUB); + if (abfd->iostream == NULL) + abfd->iostream = (PTR) real_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_if_ordinary (abfd->filename); +#endif + abfd->iostream = (PTR) real_fopen (abfd->filename, FOPEN_WUB); + abfd->opened_once = TRUE; + } + break; + } + + if (abfd->iostream == NULL) + bfd_set_error (bfd_error_system_call); + else + { + if (! bfd_cache_init (abfd)) + return NULL; + } + + return (FILE *) abfd->iostream; +} diff --git a/contrib/binutils-2.17/bfd/coffgen.c b/contrib/binutils-2.17/bfd/coffgen.c new file mode 100644 index 0000000000..c541e6a590 --- /dev/null +++ b/contrib/binutils-2.17/bfd/coffgen.c @@ -0,0 +1,2326 @@ +/* Support for the generic parts of COFF, for BFD. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004, 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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" + +/* 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 (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->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 = 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 (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); + void * tdata; + void * 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, (void *) internal_f, (void *) internal_a); + if (tdata == NULL) + goto fail2; + + scnhsz = bfd_coff_scnhsz (abfd); + readsize = (bfd_size_type) nscns * scnhsz; + external_sections = bfd_alloc (abfd, readsize); + if (!external_sections) + goto fail; + + if (bfd_bread ((void *) 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, (void *) 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, + (void *) (external_sections + i * scnhsz), + (void *) & 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 (bfd *abfd) +{ + bfd_size_type filhsz; + bfd_size_type aoutsz; + unsigned int nscns; + void * 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) + { + void * 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, (void *) &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 (bfd *abfd, int index) +{ + struct bfd_section *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 (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_canonicalize_symtab (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 (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 (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_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 = 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, (void *) erel, (void *) 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 = 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 (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 (bfd *ignore_abfd ATTRIBUTE_UNUSED, + asymbol *symbol) +{ + if (!bfd_family_coff (bfd_asymbol_bfd (symbol))) + return (coff_symbol_type *) NULL; + + if (bfd_asymbol_bfd (symbol)->tdata.coff_obj_data == (coff_data_type *) NULL) + return (coff_symbol_type *) NULL; + + return (coff_symbol_type *) symbol; +} + +static void +fixup_symbol_value (bfd *abfd, + coff_symbol_type *coff_symbol_ptr, + 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 *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 = 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 = 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 != 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 *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 (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 == 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, + (void *) buf, + (file_ptr) *debug_string_size_p, + (bfd_size_type) prefix_len) + || !bfd_set_section_contents (abfd, + *debug_string_section_p, + (void *) 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 (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; + void * 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 (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 (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) + { + lineno[count].u.offset += + (symbol->symbol.section->output_section->vma + + symbol->symbol.section->output_offset); + 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 (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_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 ((void *) 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 ((void *) (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 ((void *) 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) + == debug_string_section->size))); + + return TRUE; +} + +bfd_boolean +coff_write_linenumbers (bfd *abfd) +{ + asection *s; + bfd_size_type linesz; + void * 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 ((void *) & 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 (bfd *ignore_abfd ATTRIBUTE_UNUSED, asymbol *symbol) +{ + return coffsymbol (symbol)->lineno; +} + +/* This function transforms the offsets into the symbol table into + pointers to syments. */ + +static void +coff_pointerize_aux (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 (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 = sect->size; + debug_section = 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 (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 = 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 (bfd *abfd) +{ + bfd_size_type symesz; + bfd_size_type size; + void * syms; + + if (obj_coff_external_syms (abfd) != NULL) + return TRUE; + + symesz = bfd_coff_symesz (abfd); + + size = obj_raw_syment_count (abfd) * symesz; + + syms = 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 (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) + (_("%B: bad string table size %lu"), abfd, (unsigned long) strsize); + bfd_set_error (bfd_error_bad_value); + return NULL; + } + + strings = 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 (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 (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 = 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, (void *) raw_src, + (void *) & 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, (void *) raw_src, + symbol_ptr->u.syment.n_type, + symbol_ptr->u.syment.n_sclass, + (int) i, symbol_ptr->u.syment.n_numaux, + &(internal_ptr->u.auxent)); + 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 = 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; +} + +long +coff_get_reloc_upper_bound (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 (bfd *abfd) +{ + bfd_size_type amt = sizeof (coff_symbol_type); + coff_symbol_type *new = bfd_zalloc (abfd, amt); + + if (new == NULL) + return NULL; + new->symbol.section = 0; + new->native = 0; + new->lineno = NULL; + new->done_lineno = FALSE; + new->symbol.the_bfd = abfd; + + return & new->symbol; +} + +/* Make a debugging symbol. */ + +asymbol * +coff_bfd_make_debug_symbol (bfd *abfd, + void * ptr ATTRIBUTE_UNUSED, + unsigned long sz ATTRIBUTE_UNUSED) +{ + bfd_size_type amt = sizeof (coff_symbol_type); + coff_symbol_type *new = 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 = bfd_zalloc (abfd, amt); + if (!new->native) + return NULL; + new->symbol.section = bfd_abs_section_ptr; + new->symbol.flags = BSF_DEBUGGING; + new->lineno = NULL; + new->done_lineno = FALSE; + new->symbol.the_bfd = abfd; + + return & new->symbol; +} + +void +coff_get_symbol_info (bfd *abfd, asymbol *symbol, symbol_info *ret) +{ + bfd_symbol_info (symbol, ret); + + if (coffsymbol (symbol)->native != NULL + && coffsymbol (symbol)->native->fix_value) + 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 (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 (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 (bfd *abfd, + void * 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; + + fprintf (file, "(sec %2d)(fl 0x%02x)(ty %3x)(scl %3d) (nx %d) 0x", + 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); + fprintf_vma (file, val); + fprintf (file, " %s", symbol->name); + + 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; + } + /* Otherwise 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; + } + /* Otherwise 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 : ", l->line_number); + fprintf_vma (file, l->u.offset + symbol->section->vma); + l++; + } + } + } + else + { + bfd_print_symbol_vandf (abfd, (void *) 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 (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 (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 th. e 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 = 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; +} + +bfd_boolean +coff_find_inliner_info (bfd *abfd, + const char **filename_ptr, + const char **functionname_ptr, + unsigned int *line_ptr) +{ + bfd_boolean found; + + found = _bfd_dwarf2_find_inliner_info (abfd, filename_ptr, + functionname_ptr, line_ptr, + &coff_data(abfd)->dwarf2_find_line_info); + return (found); +} + +int +coff_sizeof_headers (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 (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 = 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; +} + +struct coff_comdat_info * +bfd_coff_get_comdat_section (bfd *abfd, struct bfd_section *sec) +{ + if (bfd_get_flavour (abfd) == bfd_target_coff_flavour + && coff_section_data (abfd, sec) != NULL) + return coff_section_data (abfd, sec)->comdat; + else + return NULL; +} diff --git a/contrib/binutils-2.17/bfd/config.bfd b/contrib/binutils-2.17/bfd/config.bfd new file mode 100644 index 0000000000..4fd72c1c15 --- /dev/null +++ b/contrib/binutils-2.17/bfd/config.bfd @@ -0,0 +1,1445 @@ +# 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 + +# Catch obsolete configurations. +case $targ in + m68*-apple-aux* | \ + m68*-apollo-* | \ + m68*-bull-sysv* | \ + m68*-*-rtemscoff* | \ + i960-*-rtems* | \ + or32-*-rtems* | \ + null) + if test "x$enable_obsolete" != xyes; then + echo "*** Configuration $targ is obsolete." >&2 + echo "*** Specify --enable-obsolete to build it anyway." >&2 + echo "*** Support will be REMOVED in the next major release of BINUTILS," >&2 + echo "*** unless a maintainer comes forward." >&2 + exit 1 + fi;; +esac + +case $targ in + m68*-*-lynxos* | \ + sparc-*-lynxos* | \ + vax-*-vms* | \ + arm-*-oabi | \ + thumb-*-oabi | \ + a29k-* | \ + hppa*-*-rtems* | \ + *-go32-rtems* | \ + i[3-7]86*-*-rtemscoff* | \ + mips*el-*-rtems* | \ + powerpcle-*-rtems* | \ + sparc*-*-rtemsaout* | \ + null) + echo "*** Configuration $targ is obsolete." >&2 + echo "*** Support has been REMOVED." >&2 + exit 1 + ;; +esac + +targ_cpu=`echo $targ | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +case "${targ_cpu}" in +alpha*) targ_archs=bfd_alpha_arch ;; +arm*) targ_archs=bfd_arm_arch ;; +bfin*) targ_archs=bfd_bfin_arch ;; +c30*) targ_archs=bfd_tic30_arch ;; +c4x*) targ_archs=bfd_tic4x_arch ;; +c54x*) targ_archs=bfd_tic54x_arch ;; +crisv32) targ_archs=bfd_cris_arch ;; +crx*) targ_archs=bfd_crx_arch ;; +dlx*) targ_archs=bfd_dlx_arch ;; +hppa*) targ_archs=bfd_hppa_arch ;; +i[3-7]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 ;; +maxq*) targ_archs=bfd_maxq_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 ;; +z80|r800) targ_archs=bfd_z80_arch ;; +z8k*) targ_archs=bfd_z8k_arch ;; +am33_2.0) targ_archs=bfd_mn10300_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*-*-mach3*) + 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* | alpha*-*-kfreebsd*-gnu) + 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-* | 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*-*-freebsd* | ia64*-*-netbsd* | ia64*-*-linux-* | ia64*-*-elf* | ia64*-*-kfreebsd*-gnu) + targ_defvec=bfd_elf64_ia64_little_vec + targ_selvecs="bfd_elf64_ia64_big_vec bfd_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* | sparc64-*-kfreebsd*-gnu) + targ_defvec=bfd_elf64_sparc_vec + targ_selvecs="bfd_elf32_sparc_vec sunos_big_vec" + ;; +#endif /* BFD64 */ + + am33_2.0-*-linux*) + targ_defvec=bfd_elf32_am33lin_vec + ;; + 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 + targ_cflags=-D__QNXTARGET__ + ;; + 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 -DARM_COFF_BUGFIX" + ;; + arm-*-pe*) + targ_defvec=armpe_little_vec + targ_selvecs="armpe_little_vec armpe_big_vec armpei_little_vec armpei_big_vec" + targ_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-*-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-*) + 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-* | arm*-*-conix* | \ + arm*-*-uclinux* | arm-*-kfreebsd*-gnu | \ + arm*-*-eabi* ) + targ_defvec=bfd_elf32_littlearm_vec + targ_selvecs=bfd_elf32_bigarm_vec + ;; + arm*-*-vxworks | arm*-*-windiss) + targ_defvec=bfd_elf32_littlearm_vxworks_vec + targ_selvecs=bfd_elf32_bigarm_vxworks_vec + ;; + arm*-*-symbianelf*) + targ_defvec=bfd_elf32_littlearm_symbian_vec + targ_selvecs=bfd_elf32_bigarm_symbian_vec + ;; + arm9e-*-elf) + targ_defvec=bfd_elf32_littlearm_vec + targ_selvecs=bfd_elf32_bigarm_vec + ;; + + thumb-*-coff) + targ_defvec=armcoff_little_vec + targ_selvecs=armcoff_big_vec + targ_underscore=yes + ;; + 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 + ;; + + avr-*-*) + targ_defvec=bfd_elf32_avr_vec + ;; + + bfin-*-*) + targ_defvec=bfd_elf32_bfin_vec + targ_selvecs=bfd_elf32_bfinfdpic_vec + targ_underscore=yes + ;; + + c30-*-*aout* | tic30-*-*aout*) + targ_defvec=tic30_aout_vec + ;; + c30-*-*coff* | tic30-*-*coff*) + targ_defvec=tic30_coff_vec + ;; + + c4x-*-*coff* | tic4x-*-*coff* | tic4x-*-rtems*) + 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 + ;; + + cr16c-*-elf*) + targ_defvec=bfd_elf32_cr16c_vec + targ_underscore=yes + ;; + + cris-*-* | crisv32-*-*) + targ_defvec=cris_aout_vec + targ_selvecs="bfd_elf32_us_cris_vec bfd_elf32_cris_vec ieee_vec" + targ_underscore=yes # Note: not true for bfd_elf32_cris_vec. + ;; + + crx-*-elf*) + targ_defvec=bfd_elf32_crx_vec + targ_underscore=yes + ;; + + 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 + targ_selvecs=bfd_elf32_frvfdpic_vec + ;; + + frv-*-*linux*) + targ_defvec=bfd_elf32_frvfdpic_vec + targ_selvecs=bfd_elf32_frv_vec + ;; + + h8300*-*-rtemscoff*) + targ_defvec=h8300coff_vec + targ_underscore=yes + ;; + + h8300*-*-elf | h8300*-*-rtems*) + 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-*) + 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-*) + targ_defvec=bfd_elf32_hppa_linux_vec + targ_selvecs=bfd_elf32_hppa_vec + ;; + hppa*-*-netbsd*) + targ_defvec=bfd_elf32_hppa_nbsd_vec + targ_selvecs="bfd_elf32_hppa_vec bfd_elf32_hppa_linux_vec" + ;; + hppa*-*-*elf* | hppa*-*-lites* | hppa*-*-sysv4* | 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[3-7]86-*-sco3.2v5*coff) + targ_defvec=i386coff_vec + targ_selvecs=bfd_elf32_i386_vec + ;; + i[3-7]86-*-sysv4* | i[3-7]86-*-unixware* | \ + i[3-7]86-*-elf | i[3-7]86-*-sco3.2v5* | \ + i[3-7]86-*-dgux* | i[3-7]86-*-sysv5*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs=i386coff_vec + ;; + i[3-7]86-*-solaris2*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs=i386coff_vec + targ64_selvecs=bfd_elf64_x86_64_vec + want64=true + ;; + i[3-7]86-*-kaos*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs=bfd_elf32_i386_vec + ;; + i[3-7]86-*-nto*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs=i386coff_vec + ;; + i[3-7]86-*-aros*) + targ_defvec=bfd_elf32_i386_vec + ;; + i[3-7]86-*-chorus*) + targ_defvec=bfd_elf32_i386_vec + ;; + *-*-msdosdjgpp* | *-*-go32* ) + targ_defvec=go32coff_vec + targ_selvecs="go32stubbedcoff_vec i386aout_vec" + ;; + i[3-7]86-*-sysv* | i[3-7]86-*-isc* | i[3-7]86-*-sco* | i[3-7]86-*-coff | \ + i[3-7]86-*-aix*) + targ_defvec=i386coff_vec + ;; + i[3-7]86-*-rtems*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs="i386coff_vec i386aout_vec" + ;; + i[3-7]86-*-darwin* | i[3-7]86-*-macos10* | i[3-7]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[3-7]86-sequent-bsd*) + targ_defvec=i386dynix_vec + targ_underscore=yes + ;; + i[3-7]86-*-bsd*) + targ_defvec=i386bsd_vec + targ_underscore=yes + ;; + i[3-7]86-*-freebsdaout* | i[3-7]86-*-freebsd[12].* | \ + i[3-7]86-*-freebsd[12]) + targ_defvec=i386freebsd_vec + targ_selvecs=i386bsd_vec + targ_underscore=yes + ;; + i[3-7]86-*-freebsd* | i[3-7]86-*-kfreebsd*-gnu) + 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[3-7]86-*-freebsd3* | i[3-7]86-*-freebsd4 | i[3-7]86-*-freebsd4.0*) + targ_cflags=-DOLD_FREEBSD_ABI_LABEL ;; + esac + ;; + i[3-7]86-*-netbsdelf* | i[3-7]86-*-netbsd*-gnu* | i[3-7]86-*-knetbsd*-gnu) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs=i386netbsd_vec + targ64_selvecs=bfd_elf64_x86_64_vec + ;; + i[3-7]86-*-netbsdpe*) + targ_defvec=i386pe_vec + targ_selvecs="i386pe_vec i386pei_vec bfd_elf32_i386_vec" + ;; + i[3-7]86-*-netbsdaout* | i[3-7]86-*-netbsd* | \ + i[3-7]86-*-openbsd[0-2].* | i[3-7]86-*-openbsd3.[0-3]) + targ_defvec=i386netbsd_vec + targ_selvecs="bfd_elf32_i386_vec i386bsd_vec" + targ_underscore=yes + ;; + i[3-7]86-*-openbsd*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs=i386netbsd_vec + ;; + i[3-7]86-*-netware*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs="nlm32_i386_vec i386coff_vec i386aout_vec" + ;; + i[3-7]86-*-linux*aout*) + targ_defvec=i386linux_vec + targ_selvecs=bfd_elf32_i386_vec + targ_underscore=yes + ;; + i[3-7]86-*-linux-*) + 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-*-elf*) + targ_defvec=bfd_elf64_x86_64_vec + targ_selvecs="bfd_elf32_i386_vec i386coff_vec" + ;; + x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) + targ_defvec=bfd_elf64_x86_64_vec + targ_selvecs="bfd_elf32_i386_vec i386coff_vec bfd_efi_app_ia32_vec" + ;; + x86_64-*-netbsd* | x86_64-*-openbsd*) + 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-*) + targ_defvec=bfd_elf64_x86_64_vec + targ_selvecs="bfd_elf32_i386_vec i386linux_vec bfd_efi_app_ia32_vec" + ;; +#endif + i[3-7]86-*-lynxos*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs="i386lynx_coff_vec i386lynx_aout_vec" + ;; + i[3-7]86-*-gnu*) + targ_defvec=bfd_elf32_i386_vec + ;; + i[3-7]86-*-mach* | i[3-7]86-*-osf1mk*) + targ_defvec=i386mach3_vec + targ_cflags=-DSTAT_FOR_EXEC + targ_underscore=yes + ;; + i[3-7]86-*-os9k) + targ_defvec=i386os9k_vec + ;; + i[3-7]86-*-msdos*) + targ_defvec=i386aout_vec + targ_selvecs=i386msdos_vec + ;; + i[3-7]86-*-moss*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs="i386msdos_vec i386aout_vec" + ;; + i[3-7]86-*-beospe*) + targ_defvec=i386pe_vec + targ_selvecs="i386pe_vec i386pei_vec" + ;; + i[3-7]86-*-beoself* | i[3-7]86-*-beos*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs="i386pe_vec i386pei_vec" + ;; + i[3-7]86-*-interix*) + targ_defvec=i386pei_vec + targ_selvecs="i386pe_vec" + # FIXME: This should eventually be checked at runtime. + targ_cflags=-DSTRICT_PE_FORMAT + ;; + i[3-7]86-*-rdos*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs=i386coff_vec + ;; + i[3-7]86-*-mingw32* | i[3-7]86-*-cygwin* | i[3-7]86-*-winnt | i[3-7]86-*-pe) + targ_defvec=i386pe_vec + targ_selvecs="i386pe_vec i386pei_vec bfd_elf32_i386_vec" + targ_underscore=yes + ;; + i[3-7]86-none-*) + targ_defvec=i386coff_vec + ;; + i[3-7]86-*-aout* | i[3-7]86*-*-vsta*) + targ_defvec=i386aout_vec + ;; + i[3-7]86-*-vxworks*) + targ_defvec=bfd_elf32_i386_vxworks_vec + targ_underscore=yes + ;; + i[3-7]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 + ;; + + m32c-*-elf) + targ_defvec=bfd_elf32_m32c_vec + ;; + + m32r*le-*-linux*) + targ_defvec=bfd_elf32_m32rlelin_vec + targ_selvecs="bfd_elf32_m32rlin_vec bfd_elf32_m32rlelin_vec" + ;; + + m32r*-*-linux*) + targ_defvec=bfd_elf32_m32rlin_vec + targ_selvecs="bfd_elf32_m32rlin_vec bfd_elf32_m32rlelin_vec" + ;; + + m32r*le-*-*) + targ_defvec=bfd_elf32_m32rle_vec + targ_selvecs="bfd_elf32_m32r_vec bfd_elf32_m32rle_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* | m68*-*-uclinux*) + 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-*) + 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*-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*-*-openbsd*) + targ_defvec=m88kopenbsd_vec + targ_underscore=yes + ;; + m88*-*-*) + targ_defvec=m88kbcs_vec + targ_underscore=yes + ;; + + maxq-*-coff) + targ_defvec=maxqcoff_vec + ;; + + 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_tradlittlemips_vec + targ_selvecs="bfd_elf32_tradbigmips_vec bfd_elf64_tradbigmips_vec bfd_elf64_tradlittlemips_vec ecoff_little_vec ecoff_big_vec" + ;; + mips*-*-netbsd*) + targ_defvec=bfd_elf32_tradbigmips_vec + targ_selvecs="bfd_elf32_tradlittlemips_vec bfd_elf64_tradbigmips_vec bfd_elf64_tradlittlemips_vec ecoff_big_vec ecoff_little_vec" + ;; + 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*-*-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 + ;; +#ifdef BFD64 + mips*el-*-vxworks*) + targ_defvec=bfd_elf32_littlemips_vxworks_vec + targ_selvecs="bfd_elf32_littlemips_vec bfd_elf32_bigmips_vxworks_vec bfd_elf32_bigmips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" + ;; + mips*-*-vxworks*) + targ_defvec=bfd_elf32_bigmips_vxworks_vec + targ_selvecs="bfd_elf32_bigmips_vec bfd_elf32_littlemips_vxworks_vec bfd_elf32_bigmips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" + ;; +#endif + mips*el-*-elf* | mips*el-*-vxworks* | mips*-*-chorus*) + targ_defvec=bfd_elf32_littlemips_vec + targ_selvecs="bfd_elf32_bigmips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" + ;; + mips*-*-elf* | mips*-*-rtems* | mips*-*-vxworks | mips*-*-windiss) + targ_defvec=bfd_elf32_bigmips_vec + targ_selvecs="bfd_elf32_littlemips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" + ;; + mips*-*-none) + targ_defvec=bfd_elf32_bigmips_vec + targ_selvecs="bfd_elf32_littlemips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" + ;; +#ifdef BFD64 + mips64*-*-openbsd*) + targ_defvec=bfd_elf64_tradbigmips_vec + targ_selvecs="bfd_elf32_ntradlittlemips_vec bfd_elf32_ntradbigmips_vec bfd_elf32_tradlittlemips_vec bfd_elf32_tradbigmips_vec bfd_elf64_tradlittlemips_vec" + ;; +#endif + mips*el-*-openbsd*) + targ_defvec=bfd_elf32_littlemips_vec + targ_selvecs="bfd_elf32_bigmips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec ecoff_little_vec ecoff_big_vec" + ;; + 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 + targ_underscore=yes + ;; + + mt-*-elf) + targ_defvec=bfd_elf32_mt_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.[01]) + targ_defvec=rs6000coff_vec + targ_selvecs="aix5coff64_vec" + want64=true + ;; +#ifdef BFD64 + powerpc64-*-aix5.[01]) + targ_defvec=aix5coff64_vec + targ_selvecs="rs6000coff_vec" + want64=true + ;; +#endif + powerpc-*-aix5*) + targ_cflags=-DAIX_WEAK_SUPPORT + targ_defvec=rs6000coff_vec + targ_selvecs="aix5coff64_vec" + want64=true + ;; +#ifdef BFD64 + powerpc64-*-aix5*) + targ_cflags=-DAIX_WEAK_SUPPORT + 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-* | powerpc-*-rtems* | \ + powerpc-*-chorus*) + targ_defvec=bfd_elf32_powerpc_vec + targ_selvecs="rs6000coff_vec bfd_elf32_powerpcle_vec ppcboot_vec" + targ64_selvecs="bfd_elf64_powerpc_vec bfd_elf64_powerpcle_vec" + ;; + 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*) + targ_defvec=pmac_xcoff_vec + ;; + powerpc-*-lynxos*) + targ_defvec=bfd_elf32_powerpc_vec + targ_selvecs="rs6000coff_vec" + targ_cflags=-DSMALL_ARCHIVE + ;; + 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" + ;; + powerpc-*-vxworks* | powerpc-*-windiss*) + targ_defvec=bfd_elf32_powerpc_vxworks_vec + targ_selvecs="rs6000coff_vec bfd_elf32_powerpc_vec bfd_elf32_powerpcle_vec ppcboot_vec" + targ64_selvecs="bfd_elf64_powerpc_vec bfd_elf64_powerpcle_vec" + ;; + 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-* | powerpcle-*-vxworks*) + targ_defvec=bfd_elf32_powerpcle_vec + targ_selvecs="rs6000coff_vec bfd_elf32_powerpc_vec ppcboot_vec" + targ64_selvecs="bfd_elf64_powerpc_vec bfd_elf64_powerpcle_vec" + ;; + 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 + want64=true + ;; +#ifdef BFD64 + s390x-*-linux*) + targ_defvec=bfd_elf64_s390_vec + targ_selvecs=bfd_elf32_s390_vec + ;; + s390x-*-tpf*) + targ_defvec=bfd_elf64_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 bfd_elf32_shnbsd_vec bfd_elf32_shlnbsd_vec" + ;; + sh5-*-netbsd*) + targ_defvec=bfd_elf32_sh64nbsd_vec + targ_selvecs="bfd_elf32_sh64lnbsd_vec bfd_elf64_sh64lnbsd_vec bfd_elf64_sh64nbsd_vec bfd_elf32_shnbsd_vec bfd_elf32_shlnbsd_vec" + ;; + + sh64le-*-netbsd*) + targ_defvec=bfd_elf64_sh64lnbsd_vec + targ_selvecs="bfd_elf64_sh64nbsd_vec bfd_elf32_sh64lnbsd_vec bfd_elf32_sh64nbsd_vec bfd_elf32_shnbsd_vec bfd_elf32_shlnbsd_vec" + ;; + sh64-*-netbsd*) + targ_defvec=bfd_elf64_sh64nbsd_vec + targ_selvecs="bfd_elf64_sh64lnbsd_vec bfd_elf32_sh64lnbsd_vec bfd_elf32_sh64nbsd_vec bfd_elf32_shnbsd_vec bfd_elf32_shlnbsd_vec" + ;; +#endif + + sh*l*-*-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-*-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" + ;; + sh*-*-symbianelf*) + targ_defvec=bfd_elf32_shl_symbian_vec + targ_selvecs="shlcoff_vec shlcoff_small_vec" + targ_underscore=yes + ;; + 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-*-rtemscoff*) + targ_defvec=shcoff_vec + targ_selvecs="shcoff_vec shlcoff_vec shcoff_small_vec shlcoff_small_vec" + targ_underscore=yes + ;; + sh-*-elf* | sh[1234]*-elf* | sh-*-rtems* | sh-*-kaos*) + targ_defvec=bfd_elf32_sh_vec + targ_selvecs="bfd_elf32_shl_vec shcoff_vec shlcoff_vec shcoff_small_vec shlcoff_small_vec" +#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-*-vxworks) + targ_defvec=bfd_elf32_sh_vec + targ_selvecs="bfd_elf32_shl_vec" + # FIXME None of the following are actually used on this target, but + # they're necessary for coff-sh.c (which is unconditionally used) to be + # compiled correctly. + targ_selvecs="$targ_selvecs shcoff_vec shlcoff_vec shcoff_small_vec shlcoff_small_vec" + ;; + sh-*-*) + 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-*) + targ_defvec=bfd_elf32_sparc_vec + targ_selvecs="sparclinux_vec bfd_elf64_sparc_vec sunos_big_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[0-2].* | sparc-*-openbsd3.[0-1]) + targ_defvec=sparcnetbsd_vec + targ_underscore=yes + ;; + sparc-*-openbsd*) + targ_defvec=bfd_elf32_sparc_vec + targ_selvecs=sparcnetbsd_vec + ;; + 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-*-vxworks*) + targ_defvec=bfd_elf32_sparc_vxworks_vec + targ_selvecs="bfd_elf32_sparc_vec sunos_big_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-*) + 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*-*-rtems*) + targ_defvec=bfd_elf32_sparc_vec + targ_selvecs="sunos_big_vec sparccoff_vec" + ;; + sparc*-*-*) + 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-*-openbsd*) + targ_defvec=vaxnetbsd_vec + targ_underscore=yes + ;; + + vax-*-linux-*) + targ_defvec=bfd_elf32_vax_vec + ;; + + 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 + ;; + xc16x-*-elf) + targ_defvec=bfd_elf32_xc16x_vec + ;; + + z80-*-*) + targ_defvec=z80coff_vec + targ_underscore=no + ;; + + 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.17/bfd/config.in b/contrib/binutils-2.17/bfd/config.in new file mode 100644 index 0000000000..6c738257d9 --- /dev/null +++ b/contrib/binutils-2.17/bfd/config.in @@ -0,0 +1,375 @@ +/* config.in. Generated from configure.in by autoheader. */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +#undef CRAY_STACKSEG_END + +/* Define to 1 if using `alloca.c'. */ +#undef C_ALLOCA + +/* Define to 1 if NLS is requested */ +#undef ENABLE_NLS + +/* Define to 1 if you have `alloca', as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#undef HAVE_ALLOCA_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARGZ_H + +/* Define to 1 if you have the `dcgettext' function. */ +#undef HAVE_DCGETTEXT + +/* Define to 1 if you have the declaration of `basename', and to 0 if you + don't. */ +#undef HAVE_DECL_BASENAME + +/* Define to 1 if you have the declaration of `ffs', and to 0 if you don't. */ +#undef HAVE_DECL_FFS + +/* Define to 1 if you have the declaration of `free', and to 0 if you don't. + */ +#undef HAVE_DECL_FREE + +/* Define to 1 if you have the declaration of `fseeko', and to 0 if you don't. + */ +#undef HAVE_DECL_FSEEKO + +/* Define to 1 if you have the declaration of `fseeko64', and to 0 if you + don't. */ +#undef HAVE_DECL_FSEEKO64 + +/* Define to 1 if you have the declaration of `ftello', and to 0 if you don't. + */ +#undef HAVE_DECL_FTELLO + +/* Define to 1 if you have the declaration of `ftello64', and to 0 if you + don't. */ +#undef HAVE_DECL_FTELLO64 + +/* Define to 1 if you have the declaration of `getenv', and to 0 if you don't. + */ +#undef HAVE_DECL_GETENV + +/* Define to 1 if you have the declaration of `malloc', and to 0 if you don't. + */ +#undef HAVE_DECL_MALLOC + +/* Define to 1 if you have the declaration of `realloc', and to 0 if you + don't. */ +#undef HAVE_DECL_REALLOC + +/* Define to 1 if you have the declaration of `snprintf', and to 0 if you + don't. */ +#undef HAVE_DECL_SNPRINTF + +/* Define to 1 if you have the declaration of `stpcpy', and to 0 if you don't. + */ +#undef HAVE_DECL_STPCPY + +/* Define to 1 if you have the declaration of `strstr', and to 0 if you don't. + */ +#undef HAVE_DECL_STRSTR + +/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you + don't. */ +#undef HAVE_DECL_VSNPRINTF + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_DIRENT_H + +/* Define to 1 if you have the `fcntl' function. */ +#undef HAVE_FCNTL + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `fdopen' function. */ +#undef HAVE_FDOPEN + +/* Define to 1 if you have the `fopen64' function. */ +#undef HAVE_FOPEN64 + +/* Define to 1 if you have the `fseeko' function. */ +#undef HAVE_FSEEKO + +/* Define to 1 if you have the `fseeko64' function. */ +#undef HAVE_FSEEKO64 + +/* Define to 1 if you have the `ftello' function. */ +#undef HAVE_FTELLO + +/* Define to 1 if you have the `ftello64' function. */ +#undef HAVE_FTELLO64 + +/* Define to 1 if you have the `getcwd' function. */ +#undef HAVE_GETCWD + +/* Define to 1 if you have the `getgid' function. */ +#undef HAVE_GETGID + +/* Define to 1 if you have the `getpagesize' function. */ +#undef HAVE_GETPAGESIZE + +/* Define as 1 if you have gettext and don't want to use GNU gettext. */ +#undef HAVE_GETTEXT + +/* Define to 1 if you have the `getuid' function. */ +#undef HAVE_GETUID + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define if your locale.h file contains LC_MESSAGES. */ +#undef HAVE_LC_MESSAGES + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define if has lwpstatus_t. */ +#undef HAVE_LWPSTATUS_T + +/* Define if has lwpstatus_t.pr_context. */ +#undef HAVE_LWPSTATUS_T_PR_CONTEXT + +/* Define if has lwpstatus_t.pr_reg. */ +#undef HAVE_LWPSTATUS_T_PR_REG + +/* Define if has lwpxstatus_t. */ +#undef HAVE_LWPXSTATUS_T + +/* Define to 1 if you have the `madvise' function. */ +#undef HAVE_MADVISE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the `mprotect' function. */ +#undef HAVE_MPROTECT + +/* Define to 1 if you have the `munmap' function. */ +#undef HAVE_MUNMAP + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +#undef HAVE_NDIR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NL_TYPES_H + +/* Define if has prpsinfo32_t. */ +#undef HAVE_PRPSINFO32_T + +/* Define if has prpsinfo_t. */ +#undef HAVE_PRPSINFO_T + +/* Define if has prstatus32_t. */ +#undef HAVE_PRSTATUS32_T + +/* Define if has prstatus32_t.pr_who. */ +#undef HAVE_PRSTATUS32_T_PR_WHO + +/* Define if has prstatus_t. */ +#undef HAVE_PRSTATUS_T + +/* Define if has prstatus_t.pr_who. */ +#undef HAVE_PRSTATUS_T_PR_WHO + +/* Define if has psinfo32_t. */ +#undef HAVE_PSINFO32_T + +/* Define if has psinfo_t. */ +#undef HAVE_PSINFO_T + +/* Define if has pstatus32_t. */ +#undef HAVE_PSTATUS32_T + +/* Define if has pstatus_t. */ +#undef HAVE_PSTATUS_T + +/* Define to 1 if you have the `putenv' function. */ +#undef HAVE_PUTENV + +/* Define if has pxstatus_t. */ +#undef HAVE_PXSTATUS_T + +/* Define to 1 if you have the `setenv' function. */ +#undef HAVE_SETENV + +/* Define to 1 if you have the `setitimer' function. */ +#undef HAVE_SETITIMER + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the stpcpy function */ +#undef HAVE_STPCPY + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strtoull' function. */ +#undef HAVE_STRTOULL + +/* Define if struct core_dumpx has member c_impl */ +#undef HAVE_ST_C_IMPL + +/* Define to 1 if you have the `sysconf' function. */ +#undef HAVE_SYSCONF + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_SYS_DIR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FILE_H + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_SYS_NDIR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PROCFS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_VALUES_H + +/* Define if has win32_pstatus_t. */ +#undef HAVE_WIN32_PSTATUS_T + +/* Define to 1 if you have the `__argz_count' function. */ +#undef HAVE___ARGZ_COUNT + +/* Define to 1 if you have the `__argz_next' function. */ +#undef HAVE___ARGZ_NEXT + +/* Define to 1 if you have the `__argz_stringify' function. */ +#undef HAVE___ARGZ_STRINGIFY + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of a `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* The size of a `long long', as computed by sizeof. */ +#undef SIZEOF_LONG_LONG + +/* The size of a `off_t', as computed by sizeof. */ +#undef SIZEOF_OFF_T + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +#undef STACK_DIRECTION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if you can safely include both and . */ +#undef STRING_WITH_STRINGS + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Name of host specific header file to include in trad-core.c. */ +#undef TRAD_HEADER + +/* Use b modifier when opening binary files? */ +#undef USE_BINARY_FOPEN + +/* Use mmap if it's available? */ +#undef USE_MMAP + +/* Define if we should default to creating read-only plt entries */ +#undef USE_SECUREPLT + +/* Version number of package */ +#undef VERSION + +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to `long' if does not define. */ +#undef off_t + +/* Define to `unsigned' if does not define. */ +#undef size_t diff --git a/contrib/binutils-2.17/bfd/corefile.c b/contrib/binutils-2.17/bfd/corefile.c new file mode 100644 index 0000000000..602de911a2 --- /dev/null +++ b/contrib/binutils-2.17/bfd/corefile.c @@ -0,0 +1,165 @@ +/* Core file generic interface routines for BFD. + Copyright 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2002, 2003, 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* +SECTION + Core files + +SUBSECTION + Core file functions + +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 (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 (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 (bfd *core_bfd, 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)); +} + +/* +FUNCTION + generic_core_file_matches_executable_p + +SYNOPSIS + bfd_boolean generic_core_file_matches_executable_p + (bfd *core_bfd, bfd *exec_bfd); + +DESCRIPTION + Return TRUE if the core file attached to @var{core_bfd} + was generated by a run of the executable file attached + to @var{exec_bfd}. The match is based on executable + basenames only. + + Note: When not able to determine the core file failing + command or the executable name, we still return TRUE even + though we're not sure that core file and executable match. + This is to avoid generating a false warning in situations + where we really don't know whether they match or not. +*/ + +bfd_boolean +generic_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd) +{ + char *exec; + char *core; + char *last_slash; + + if (exec_bfd == NULL || core_bfd == NULL) + return TRUE; + + /* The cast below is to avoid a compiler warning due to the assignment + of the const char * returned by bfd_core_file_failing_command to a + non-const char *. In this case, the assignement does not lead to + breaking the const, as we're only reading the string. */ + + core = (char *) bfd_core_file_failing_command (core_bfd); + if (core == NULL) + return TRUE; + + exec = bfd_get_filename (exec_bfd); + if (exec == NULL) + return TRUE; + + last_slash = strrchr (core, '/'); + if (last_slash != NULL) + core = last_slash + 1; + + last_slash = strrchr (exec, '/'); + if (last_slash != NULL) + exec = last_slash + 1; + + return strcmp (exec, core) == 0; +} + diff --git a/contrib/binutils-2.17/bfd/cpu-i386.c b/contrib/binutils-2.17/bfd/cpu-i386.c new file mode 100644 index 0000000000..8886c47d0a --- /dev/null +++ b/contrib/binutils-2.17/bfd/cpu-i386.c @@ -0,0 +1,103 @@ +/* BFD support for the Intel 386 architecture. + Copyright 1992, 1994, 1995, 1996, 1998, 2000, 2001, 2002, 2004 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +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, + FALSE, + bfd_default_compatible, + bfd_default_scan, + 0 +}; + +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, + &bfd_x86_64_arch_intel_syntax +}; + +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_i386_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, + FALSE, + 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.17/bfd/doc/aoutx.texi b/contrib/binutils-2.17/bfd/doc/aoutx.texi new file mode 100644 index 0000000000..7cf9787f10 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/aoutx.texi @@ -0,0 +1,213 @@ +@section a.out backends + + +@strong{Description}@* +BFD supports a number of different flavours of a.out format, +though the major differences are only the sizes of the +structures on disk, and the shape of the relocation +information. + +The support is split into a basic support file @file{aoutx.h} +and other files which derive functions from the base. One +derivation file is @file{aoutf1.h} (for a.out flavour 1), and +adds to the basic a.out functions support for sun3, sun4, 386 +and 29k a.out files, to create a target jump vector for a +specific target. + +This information is further split out into more specific files +for each machine, including @file{sunos.c} for sun3 and sun4, +@file{newsos3.c} for the Sony NEWS, and @file{demo64.c} for a +demonstration of a 64 bit a.out format. + +The base file @file{aoutx.h} defines general mechanisms for +reading and writing records to and from disk and various +other methods which BFD requires. It is included by +@file{aout32.c} and @file{aout64.c} to form the names +@code{aout_32_swap_exec_header_in}, @code{aout_64_swap_exec_header_in}, etc. + +As an example, this is what goes on to make the back end for a +sun4, from @file{aout32.c}: + +@example + #define ARCH_SIZE 32 + #include "aoutx.h" +@end example + +Which exports names: + +@example + ... + aout_32_canonicalize_reloc + aout_32_find_nearest_line + aout_32_get_lineno + aout_32_get_reloc_upper_bound + ... +@end example + +from @file{sunos.c}: + +@example + #define TARGET_NAME "a.out-sunos-big" + #define VECNAME sunos_big_vec + #include "aoutf1.h" +@end example + +requires all the names from @file{aout32.c}, and produces the jump vector + +@example + sunos_big_vec +@end example + +The file @file{host-aout.c} is a special case. It is for a large set +of hosts that use ``more or less standard'' a.out files, and +for which cross-debugging is not interesting. It uses the +standard 32-bit a.out support routines, but determines the +file offsets and addresses of the text, data, and BSS +sections, the machine architecture and machine type, and the +entry point address, in a host-dependent manner. Once these +values have been determined, generic code is used to handle +the object file. + +When porting it to run on a new system, you must supply: + +@example + HOST_PAGE_SIZE + HOST_SEGMENT_SIZE + HOST_MACHINE_ARCH (optional) + HOST_MACHINE_MACHINE (optional) + HOST_TEXT_START_ADDR + HOST_STACK_END_ADDR +@end example + +in the file @file{../include/sys/h-@var{XXX}.h} (for your host). These +values, plus the structures and macros defined in @file{a.out.h} on +your host system, will produce a BFD target that will access +ordinary a.out files on your host. To configure a new machine +to use @file{host-aout.c}, specify: + +@example + TDEFAULTS = -DDEFAULT_VECTOR=host_aout_big_vec + TDEPFILES= host-aout.o trad-core.o +@end example + +in the @file{config/@var{XXX}.mt} file, and modify @file{configure.in} +to use the +@file{@var{XXX}.mt} file (by setting "@code{bfd_target=XXX}") when your +configuration is selected. + +@subsection Relocations + + +@strong{Description}@* +The file @file{aoutx.h} provides for both the @emph{standard} +and @emph{extended} forms of a.out relocation records. + +The standard records contain only an +address, a symbol index, and a type field. The extended records +(used on 29ks and sparcs) also have a full integer for an +addend. + +@subsection Internal entry points + + +@strong{Description}@* +@file{aoutx.h} exports several routines for accessing the +contents of an a.out file, which are gathered and exported in +turn by various format specific files (eg sunos.c). + +@findex aout_@var{size}_swap_exec_header_in +@subsubsection @code{aout_@var{size}_swap_exec_header_in} +@strong{Synopsis} +@example +void aout_@var{size}_swap_exec_header_in, + (bfd *abfd, + struct external_exec *bytes, + struct internal_exec *execp); +@end example +@strong{Description}@* +Swap the information in an executable header @var{raw_bytes} taken +from a raw byte stream memory image into the internal exec header +structure @var{execp}. + +@findex aout_@var{size}_swap_exec_header_out +@subsubsection @code{aout_@var{size}_swap_exec_header_out} +@strong{Synopsis} +@example +void aout_@var{size}_swap_exec_header_out + (bfd *abfd, + struct internal_exec *execp, + struct external_exec *raw_bytes); +@end example +@strong{Description}@* +Swap the information in an internal exec header structure +@var{execp} into the buffer @var{raw_bytes} ready for writing to disk. + +@findex aout_@var{size}_some_aout_object_p +@subsubsection @code{aout_@var{size}_some_aout_object_p} +@strong{Synopsis} +@example +const bfd_target *aout_@var{size}_some_aout_object_p + (bfd *abfd, + struct internal_exec *execp, + const bfd_target *(*callback_to_real_object_p) (bfd *)); +@end example +@strong{Description}@* +Some a.out variant thinks that the file open in @var{abfd} +checking is an a.out file. Do some more checking, and set up +for access if it really is. Call back to the calling +environment's "finish up" function just before returning, to +handle any last-minute setup. + +@findex aout_@var{size}_mkobject +@subsubsection @code{aout_@var{size}_mkobject} +@strong{Synopsis} +@example +bfd_boolean aout_@var{size}_mkobject, (bfd *abfd); +@end example +@strong{Description}@* +Initialize BFD @var{abfd} for use with a.out files. + +@findex aout_@var{size}_machine_type +@subsubsection @code{aout_@var{size}_machine_type} +@strong{Synopsis} +@example +enum machine_type aout_@var{size}_machine_type + (enum bfd_architecture arch, + unsigned long machine, + bfd_boolean *unknown); +@end example +@strong{Description}@* +Keep track of machine architecture and machine type for +a.out's. Return the @code{machine_type} for a particular +architecture and machine, or @code{M_UNKNOWN} if that exact architecture +and machine can't be represented in a.out format. + +If the architecture is understood, machine type 0 (default) +is always understood. + +@findex aout_@var{size}_set_arch_mach +@subsubsection @code{aout_@var{size}_set_arch_mach} +@strong{Synopsis} +@example +bfd_boolean aout_@var{size}_set_arch_mach, + (bfd *, + enum bfd_architecture arch, + unsigned long machine); +@end example +@strong{Description}@* +Set the architecture and the machine of the BFD @var{abfd} to the +values @var{arch} and @var{machine}. Verify that @var{abfd}'s format +can support the architecture required. + +@findex aout_@var{size}_new_section_hook +@subsubsection @code{aout_@var{size}_new_section_hook} +@strong{Synopsis} +@example +bfd_boolean aout_@var{size}_new_section_hook, + (bfd *abfd, + asection *newsect); +@end example +@strong{Description}@* +Called by the BFD in response to a @code{bfd_make_section} +request. + diff --git a/contrib/binutils-2.17/bfd/doc/archive.texi b/contrib/binutils-2.17/bfd/doc/archive.texi new file mode 100644 index 0000000000..3d0a97d4b8 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/archive.texi @@ -0,0 +1,99 @@ +@section Archives + + +@strong{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 @code{bfd_openr_next_archived_file} 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 +@code{next} pointer in a BFD. The first one is findable through +the @code{archive_head} slot of the archive. Set it with +@code{bfd_set_archive_head} (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 @code{archive.c}. + +@subsection Archive functions + + +@findex bfd_get_next_mapent +@subsubsection @code{bfd_get_next_mapent} +@strong{Synopsis} +@example +symindex bfd_get_next_mapent + (bfd *abfd, symindex previous, carsym **sym); +@end example +@strong{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 @code{BFD_NO_MORE_SYMBOLS} as the @var{previous} entry to get +the first one; returns @code{BFD_NO_MORE_SYMBOLS} when you've already +got the last one. + +A @code{carsym} is a canonical archive symbol. The only +user-visible element is its name, a null-terminated string. + +@findex bfd_set_archive_head +@subsubsection @code{bfd_set_archive_head} +@strong{Synopsis} +@example +bfd_boolean bfd_set_archive_head (bfd *output, bfd *new_head); +@end example +@strong{Description}@* +Set the head of the chain of +BFDs contained in the archive @var{output} to @var{new_head}. + +@findex bfd_openr_next_archived_file +@subsubsection @code{bfd_openr_next_archived_file} +@strong{Synopsis} +@example +bfd *bfd_openr_next_archived_file (bfd *archive, bfd *previous); +@end example +@strong{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. + diff --git a/contrib/binutils-2.17/bfd/doc/archures.texi b/contrib/binutils-2.17/bfd/doc/archures.texi new file mode 100644 index 0000000000..bf72179dad --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/archures.texi @@ -0,0 +1,585 @@ +@section Architectures +BFD keeps one atom in a BFD describing the +architecture of the data attached to the BFD: a pointer to a +@code{bfd_arch_info_type}. + +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 +@code{SELECT_ARCHITECTURES}. 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 + + +@strong{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. +@example +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_mcf_isa_a_nodiv 9 +#define bfd_mach_mcf_isa_a 10 +#define bfd_mach_mcf_isa_a_mac 11 +#define bfd_mach_mcf_isa_a_emac 12 +#define bfd_mach_mcf_isa_aplus 13 +#define bfd_mach_mcf_isa_aplus_mac 14 +#define bfd_mach_mcf_isa_aplus_emac 15 +#define bfd_mach_mcf_isa_b_nousp 16 +#define bfd_mach_mcf_isa_b_nousp_mac 17 +#define bfd_mach_mcf_isa_b_nousp_emac 18 +#define bfd_mach_mcf_isa_b 19 +#define bfd_mach_mcf_isa_b_mac 20 +#define bfd_mach_mcf_isa_b_emac 21 +#define bfd_mach_mcf_isa_b_float 22 +#define bfd_mach_mcf_isa_b_float_mac 23 +#define bfd_mach_mcf_isa_b_float_emac 24 + 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_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) +/* Nonzero if MACH is a 64 bit sparc architecture. */ +#define bfd_mach_sparc_64bit_p(mach) \ + ((mach) >= bfd_mach_sparc_v9 && (mach) != bfd_mach_sparc_v8plusb) + 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_mips7000 7000 +#define bfd_mach_mips8000 8000 +#define bfd_mach_mips9000 9000 +#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 +#define bfd_mach_mipsisa64r2 65 + 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_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 +#define bfd_mach_h8300sx 6 +#define bfd_mach_h8300sxn 7 + 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 */ +#define bfd_mach_hppa10 10 +#define bfd_mach_hppa11 11 +#define bfd_mach_hppa20 20 +#define bfd_mach_hppa20w 25 + 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_sh2a 0x2a +#define bfd_mach_sh2a_nofpu 0x2b +#define bfd_mach_sh2a_nofpu_or_sh4_nommu_nofpu 0x2a1 +#define bfd_mach_sh2a_nofpu_or_sh3_nommu 0x2a2 +#define bfd_mach_sh2a_or_sh4 0x2a3 +#define bfd_mach_sh2a_or_sh3e 0x2a4 +#define bfd_mach_sh2e 0x2e +#define bfd_mach_sh3 0x30 +#define bfd_mach_sh3_nommu 0x31 +#define bfd_mach_sh3_dsp 0x3d +#define bfd_mach_sh3e 0x3e +#define bfd_mach_sh4 0x40 +#define bfd_mach_sh4_nofpu 0x41 +#define bfd_mach_sh4_nommu_nofpu 0x42 +#define bfd_mach_sh4a 0x4a +#define bfd_mach_sh4a_nofpu 0x4b +#define bfd_mach_sh4al_dsp 0x4d +#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' +#define bfd_mach_v850e1 '1' + 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_m32c, /* Renesas M16C/M32C. */ +#define bfd_mach_m16c 0x75 +#define bfd_mach_m32c 0x78 + bfd_arch_m32r, /* Renesas M32R (formerly Mitsubishi M32R/D) */ +#define bfd_mach_m32r 1 /* For backwards compatibility. */ +#define bfd_mach_m32rx 'x' +#define bfd_mach_m32r2 '2' + bfd_arch_mn10200, /* Matsushita MN10200 */ + bfd_arch_mn10300, /* Matsushita MN10300 */ +#define bfd_mach_mn10300 300 +#define bfd_mach_am33 330 +#define bfd_mach_am33_2 332 + 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_fr450 450 +#define bfd_mach_frvtomcat 499 /* fr500 prototype */ +#define bfd_mach_fr500 500 +#define bfd_mach_fr550 550 + 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_mt, +#define bfd_mach_ms1 1 +#define bfd_mach_mrisc2 2 +#define bfd_mach_ms2 3 + 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_bfin, /* ADI Blackfin */ +#define bfd_mach_bfin 1 + bfd_arch_cr16c, /* National Semiconductor CompactRISC. */ +#define bfd_mach_cr16c 1 + bfd_arch_crx, /* National Semiconductor CRX. */ +#define bfd_mach_crx 1 + bfd_arch_cris, /* Axis CRIS */ +#define bfd_mach_cris_v0_v10 255 +#define bfd_mach_cris_v32 32 +#define bfd_mach_cris_v10_v32 1032 + 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_msp11 11 +#define bfd_mach_msp110 110 +#define bfd_mach_msp12 12 +#define bfd_mach_msp13 13 +#define bfd_mach_msp14 14 +#define bfd_mach_msp15 15 +#define bfd_mach_msp16 16 +#define bfd_mach_msp21 21 +#define bfd_mach_msp31 31 +#define bfd_mach_msp32 32 +#define bfd_mach_msp33 33 +#define bfd_mach_msp41 41 +#define bfd_mach_msp42 42 +#define bfd_mach_msp43 43 +#define bfd_mach_msp44 44 + bfd_arch_xc16x, /* Infineon's XC16X Series. */ +#define bfd_mach_xc16x 1 +#define bfd_mach_xc16xl 2 +#define bfd_mach_xc16xs 3 + bfd_arch_xtensa, /* Tensilica's Xtensa cores. */ +#define bfd_mach_xtensa 1 + bfd_arch_maxq, /* Dallas MAXQ 10/20 */ +#define bfd_mach_maxq10 10 +#define bfd_mach_maxq20 20 + bfd_arch_z80, +#define bfd_mach_z80strict 1 /* No undocumented opcodes. */ +#define bfd_mach_z80 3 /* With ixl, ixh, iyl, and iyh. */ +#define bfd_mach_z80full 7 /* All undocumented instructions. */ +#define bfd_mach_r800 11 /* R800: successor with multiplication. */ + bfd_arch_last + @}; +@end example + +@subsection bfd_arch_info + + +@strong{Description}@* +This structure contains information on architectures for use +within BFD. +@example + +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 @code{next}. */ + bfd_boolean the_default; + const struct bfd_arch_info * (*compatible) + (const struct bfd_arch_info *a, const struct bfd_arch_info *b); + + bfd_boolean (*scan) (const struct bfd_arch_info *, const char *); + + const struct bfd_arch_info *next; +@} +bfd_arch_info_type; + +@end example + +@findex bfd_printable_name +@subsubsection @code{bfd_printable_name} +@strong{Synopsis} +@example +const char *bfd_printable_name (bfd *abfd); +@end example +@strong{Description}@* +Return a printable string representing the architecture and machine +from the pointer to the architecture info structure. + +@findex bfd_scan_arch +@subsubsection @code{bfd_scan_arch} +@strong{Synopsis} +@example +const bfd_arch_info_type *bfd_scan_arch (const char *string); +@end example +@strong{Description}@* +Figure out if BFD supports any cpu which could be described with +the name @var{string}. Return a pointer to an @code{arch_info} +structure if a machine is found, otherwise NULL. + +@findex bfd_arch_list +@subsubsection @code{bfd_arch_list} +@strong{Synopsis} +@example +const char **bfd_arch_list (void); +@end example +@strong{Description}@* +Return a freshly malloced NULL-terminated vector of the names +of all the valid BFD architectures. Do not modify the names. + +@findex bfd_arch_get_compatible +@subsubsection @code{bfd_arch_get_compatible} +@strong{Synopsis} +@example +const bfd_arch_info_type *bfd_arch_get_compatible + (const bfd *abfd, const bfd *bbfd, bfd_boolean accept_unknowns); +@end example +@strong{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 @code{arch_info} structure +describing the compatible machine. + +@findex bfd_default_arch_struct +@subsubsection @code{bfd_default_arch_struct} +@strong{Description}@* +The @code{bfd_default_arch_struct} is an item of +@code{bfd_arch_info_type} 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. +@example +extern const bfd_arch_info_type bfd_default_arch_struct; +@end example + +@findex bfd_set_arch_info +@subsubsection @code{bfd_set_arch_info} +@strong{Synopsis} +@example +void bfd_set_arch_info (bfd *abfd, const bfd_arch_info_type *arg); +@end example +@strong{Description}@* +Set the architecture info of @var{abfd} to @var{arg}. + +@findex bfd_default_set_arch_mach +@subsubsection @code{bfd_default_set_arch_mach} +@strong{Synopsis} +@example +bfd_boolean bfd_default_set_arch_mach + (bfd *abfd, enum bfd_architecture arch, unsigned long mach); +@end example +@strong{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 @code{arch_info} +pointer. + +@findex bfd_get_arch +@subsubsection @code{bfd_get_arch} +@strong{Synopsis} +@example +enum bfd_architecture bfd_get_arch (bfd *abfd); +@end example +@strong{Description}@* +Return the enumerated type which describes the BFD @var{abfd}'s +architecture. + +@findex bfd_get_mach +@subsubsection @code{bfd_get_mach} +@strong{Synopsis} +@example +unsigned long bfd_get_mach (bfd *abfd); +@end example +@strong{Description}@* +Return the long type which describes the BFD @var{abfd}'s +machine. + +@findex bfd_arch_bits_per_byte +@subsubsection @code{bfd_arch_bits_per_byte} +@strong{Synopsis} +@example +unsigned int bfd_arch_bits_per_byte (bfd *abfd); +@end example +@strong{Description}@* +Return the number of bits in one of the BFD @var{abfd}'s +architecture's bytes. + +@findex bfd_arch_bits_per_address +@subsubsection @code{bfd_arch_bits_per_address} +@strong{Synopsis} +@example +unsigned int bfd_arch_bits_per_address (bfd *abfd); +@end example +@strong{Description}@* +Return the number of bits in one of the BFD @var{abfd}'s +architecture's addresses. + +@findex bfd_default_compatible +@subsubsection @code{bfd_default_compatible} +@strong{Synopsis} +@example +const bfd_arch_info_type *bfd_default_compatible + (const bfd_arch_info_type *a, const bfd_arch_info_type *b); +@end example +@strong{Description}@* +The default function for testing for compatibility. + +@findex bfd_default_scan +@subsubsection @code{bfd_default_scan} +@strong{Synopsis} +@example +bfd_boolean bfd_default_scan + (const struct bfd_arch_info *info, const char *string); +@end example +@strong{Description}@* +The default function for working out whether this is an +architecture hit and a machine hit. + +@findex bfd_get_arch_info +@subsubsection @code{bfd_get_arch_info} +@strong{Synopsis} +@example +const bfd_arch_info_type *bfd_get_arch_info (bfd *abfd); +@end example +@strong{Description}@* +Return the architecture info struct in @var{abfd}. + +@findex bfd_lookup_arch +@subsubsection @code{bfd_lookup_arch} +@strong{Synopsis} +@example +const bfd_arch_info_type *bfd_lookup_arch + (enum bfd_architecture arch, unsigned long machine); +@end example +@strong{Description}@* +Look for the architecture 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. + +@findex bfd_printable_arch_mach +@subsubsection @code{bfd_printable_arch_mach} +@strong{Synopsis} +@example +const char *bfd_printable_arch_mach + (enum bfd_architecture arch, unsigned long machine); +@end example +@strong{Description}@* +Return a printable string representing the architecture and +machine type. + +This routine is depreciated. + +@findex bfd_octets_per_byte +@subsubsection @code{bfd_octets_per_byte} +@strong{Synopsis} +@example +unsigned int bfd_octets_per_byte (bfd *abfd); +@end example +@strong{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. + +@findex bfd_arch_mach_octets_per_byte +@subsubsection @code{bfd_arch_mach_octets_per_byte} +@strong{Synopsis} +@example +unsigned int bfd_arch_mach_octets_per_byte + (enum bfd_architecture arch, unsigned long machine); +@end example +@strong{Description}@* +See bfd_octets_per_byte. + +This routine is provided for those cases where a bfd * is not +available + diff --git a/contrib/binutils-2.17/bfd/doc/bfd.texinfo b/contrib/binutils-2.17/bfd/doc/bfd.texinfo new file mode 100644 index 0000000000..432e052644 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/bfd.texinfo @@ -0,0 +1,336 @@ +\input texinfo.tex +@setfilename bfd.info +@c Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1997, 2000, +@c 2001, 2002, 2003 +@c Free Software Foundation, Inc. +@c +@synindex fn cp + +@ifinfo +@format +START-INFO-DIR-ENTRY +* Bfd: (bfd). The Binary File Descriptor library. +END-INFO-DIR-ENTRY +@end format +@end ifinfo + +@ifinfo +This file documents the BFD library. + +Copyright (C) 1991, 2000, 2001, 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''. + +@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 +@iftex +@c@finalout +@setchapternewpage on +@c@setchapternewpage odd +@settitle LIB BFD, the Binary File Descriptor Library +@titlepage +@title{libbfd} +@subtitle{The Binary File Descriptor Library} +@sp 1 +@subtitle First Edition---BFD version < 3.0 % Since no product is stable berfore version 3.0 :-) +@subtitle Original Document Created: April 1991 +@author {Steve Chamberlain} +@author {Cygnus Support} +@page + +@tex +\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$ +\xdef\manvers{1.5} % For use in headers, footers too +{\parskip=0pt +\hfill Free Software Foundation\par +\hfill sac\@www.gnu.org\par +\hfill {\it BFD}, \manvers\par +\hfill \TeX{}info \texinfoversion\par +} +\global\parindent=0pt % Steve likes it this way +@end tex + +@vskip 0pt plus 1filll +Copyright @copyright{} 1991, 2001, 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 +@end iftex + +@node Top, Overview, (dir), (dir) +@ifinfo +This file documents the binary file descriptor library libbfd. +@end ifinfo + +@menu +* Overview:: Overview of BFD +* BFD front end:: BFD front end +* BFD back ends:: BFD back ends +* GNU Free Documentation License:: GNU Free Documentation License +* Index:: Index +@end menu + +@node Overview, BFD front end, Top, Top +@chapter Introduction +@cindex BFD +@cindex what is it? +BFD is a package which allows applications to use the +same routines to operate on object files whatever the object file +format. A new object file format can be supported simply by +creating a new BFD back end and adding it to the library. + +BFD is split into two parts: the front end, and the back ends (one for +each object file format). +@itemize @bullet +@item The front end of BFD provides the interface to the user. It manages +memory and various canonical data structures. The front end also +decides which back end to use and when to call back end routines. +@item The back ends provide BFD its view of the real world. Each back +end provides a set of calls which the BFD front end can use to maintain +its canonical form. The back ends also may keep around information for +their own use, for greater efficiency. +@end itemize +@menu +* History:: History +* How It Works:: How It Works +* What BFD Version 2 Can Do:: What BFD Version 2 Can Do +@end menu + +@node History, How It Works, Overview, Overview +@section History + +One spur behind BFD was the desire, on the part of the GNU 960 team at +Intel Oregon, for interoperability of applications on their COFF and +b.out file formats. Cygnus was providing GNU support for the team, and +was contracted to provide the required functionality. + +The name came from a conversation David Wallace was having with Richard +Stallman about the library: RMS said that it would be quite hard---David +said ``BFD''. Stallman was right, but the name stuck. + +At the same time, Ready Systems wanted much the same thing, but for +different object file formats: IEEE-695, Oasys, Srecords, a.out and 68k +coff. + +BFD was first implemented by members of Cygnus Support; Steve +Chamberlain (@code{sac@@cygnus.com}), John Gilmore +(@code{gnu@@cygnus.com}), K. Richard Pixley (@code{rich@@cygnus.com}) +and David Henkel-Wallace (@code{gumby@@cygnus.com}). + + + +@node How It Works, What BFD Version 2 Can Do, History, Overview +@section How To Use BFD + +To use the library, include @file{bfd.h} and link with @file{libbfd.a}. + +BFD provides a common interface to the parts of an object file +for a calling application. + +When an application sucessfully opens a target file (object, archive, or +whatever), a pointer to an internal structure is returned. This pointer +points to a structure called @code{bfd}, described in +@file{bfd.h}. Our convention is to call this pointer a BFD, and +instances of it within code @code{abfd}. All operations on +the target object file are applied as methods to the BFD. The mapping is +defined within @code{bfd.h} in a set of macros, all beginning +with @samp{bfd_} to reduce namespace pollution. + +For example, this sequence does what you would probably expect: +return the number of sections in an object file attached to a BFD +@code{abfd}. + +@example +@c @cartouche +#include "bfd.h" + +unsigned int number_of_sections (abfd) +bfd *abfd; +@{ + return bfd_count_sections (abfd); +@} +@c @end cartouche +@end example + +The abstraction used within BFD is that an object file has: + +@itemize @bullet +@item +a header, +@item +a number of sections containing raw data (@pxref{Sections}), +@item +a set of relocations (@pxref{Relocations}), and +@item +some symbol information (@pxref{Symbols}). +@end itemize +@noindent +Also, BFDs opened for archives have the additional attribute of an index +and contain subordinate BFDs. This approach is fine for a.out and coff, +but loses efficiency when applied to formats such as S-records and +IEEE-695. + +@node What BFD Version 2 Can Do, , How It Works, Overview +@section What BFD Version 2 Can Do +@include bfdsumm.texi + +@node BFD front end, BFD back ends, Overview, Top +@chapter BFD Front End +@include bfdt.texi +@include bfdio.texi + +@menu +* Memory Usage:: +* Initialization:: +* Sections:: +* Symbols:: +* Archives:: +* Formats:: +* Relocations:: +* Core Files:: +* Targets:: +* Architectures:: +* Opening and Closing:: +* Internal:: +* File Caching:: +* Linker Functions:: +* Hash Tables:: +@end menu + +@node Memory Usage, Initialization, BFD front end, BFD front end +@section Memory Usage +BFD keeps all of its internal structures in obstacks. There is one obstack +per open BFD file, into which the current state is stored. When a BFD is +closed, the obstack is deleted, and so everything which has been +allocated by BFD for the closing file is thrown away. + +BFD does not free anything created by an application, but pointers into +@code{bfd} structures become invalid on a @code{bfd_close}; for example, +after a @code{bfd_close} the vector passed to +@code{bfd_canonicalize_symtab} is still around, since it has been +allocated by the application, but the data that it pointed to are +lost. + +The general rule is to not close a BFD until all operations dependent +upon data from the BFD have been completed, or all the data from within +the file has been copied. To help with the management of memory, there +is a function (@code{bfd_alloc_size}) which returns the number of bytes +in obstacks associated with the supplied BFD. This could be used to +select the greediest open BFD, close it to reclaim the memory, perform +some operation and reopen the BFD again, to get a fresh copy of the data +structures. + +@node Initialization, Sections, Memory Usage, BFD front end +@include init.texi + +@node Sections, Symbols, Initialization, BFD front end +@include section.texi + +@node Symbols, Archives, Sections, BFD front end +@include syms.texi + +@node Archives, Formats, Symbols, BFD front end +@include archive.texi + +@node Formats, Relocations, Archives, BFD front end +@include format.texi + +@node Relocations, Core Files, Formats, BFD front end +@include reloc.texi + +@node Core Files, Targets, Relocations, BFD front end +@include core.texi + +@node Targets, Architectures, Core Files, BFD front end +@include targets.texi + +@node Architectures, Opening and Closing, Targets, BFD front end +@include archures.texi + +@node Opening and Closing, Internal, Architectures, BFD front end +@include opncls.texi + +@node Internal, File Caching, Opening and Closing, BFD front end +@include libbfd.texi + +@node File Caching, Linker Functions, Internal, BFD front end +@include cache.texi + +@node Linker Functions, Hash Tables, File Caching, BFD front end +@include linker.texi + +@node Hash Tables, , Linker Functions, BFD front end +@include hash.texi + +@node BFD back ends, GNU Free Documentation License, BFD front end, Top +@chapter BFD back ends +@menu +* What to Put Where:: +* aout :: a.out backends +* coff :: coff backends +* elf :: elf backends +* mmo :: mmo backend +@ignore +* oasys :: oasys backends +* ieee :: ieee backend +* srecord :: s-record backend +@end ignore +@end menu +@node What to Put Where, aout, BFD back ends, BFD back ends +All of BFD lives in one directory. + +@node aout, coff, What to Put Where, BFD back ends +@include aoutx.texi + +@node coff, elf, aout, BFD back ends +@include coffcode.texi + +@node elf, mmo, coff, BFD back ends +@include elf.texi +@c Leave this out until the file has some actual contents... +@c @include elfcode.texi + +@node mmo, , elf, BFD back ends +@include mmo.texi + +@node GNU Free Documentation License, Index, BFD back ends, Top +@include fdl.texi + +@node Index, , GNU Free Documentation License, Top +@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.17/bfd/doc/bfdint.texi b/contrib/binutils-2.17/bfd/doc/bfdint.texi new file mode 100644 index 0000000000..98826fd520 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/bfdint.texi @@ -0,0 +1,1890 @@ +\input texinfo +@c Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, +@c 2000, 2001, 2002, 2003, 2004 +@c Free Software Foundation, Inc. +@setfilename bfdint.info + +@settitle BFD Internals +@iftex +@titlepage +@title{BFD Internals} +@author{Ian Lance Taylor} +@author{Cygnus Solutions} +@page +@end iftex + +@node Top +@top BFD Internals +@raisesections +@cindex bfd internals + +This document describes some BFD internal information which may be +helpful when working on BFD. It is very incomplete. + +This document is not updated regularly, and may be out of date. + +The initial version of this document was written by Ian Lance Taylor +@email{ian@@cygnus.com}. + +@menu +* BFD overview:: BFD overview +* BFD guidelines:: BFD programming guidelines +* BFD target vector:: BFD target vector +* BFD generated files:: BFD generated files +* BFD multiple compilations:: Files compiled multiple times in BFD +* BFD relocation handling:: BFD relocation handling +* BFD ELF support:: BFD ELF support +* BFD glossary:: Glossary +* Index:: Index +@end menu + +@node BFD overview +@section BFD overview + +BFD is a library which provides a single interface to read and write +object files, executables, archive files, and core files in any format. + +@menu +* BFD library interfaces:: BFD library interfaces +* BFD library users:: BFD library users +* BFD view:: The BFD view of a file +* BFD blindness:: BFD loses information +@end menu + +@node BFD library interfaces +@subsection BFD library interfaces + +One way to look at the BFD library is to divide it into four parts by +type of interface. + +The first interface is the set of generic functions which programs using +the BFD library will call. These generic function normally translate +directly or indirectly into calls to routines which are specific to a +particular object file format. Many of these generic functions are +actually defined as macros in @file{bfd.h}. These functions comprise +the official BFD interface. + +The second interface is the set of functions which appear in the target +vectors. This is the bulk of the code in BFD. A target vector is a set +of function pointers specific to a particular object file format. The +target vector is used to implement the generic BFD functions. These +functions are always called through the target vector, and are never +called directly. The target vector is described in detail in @ref{BFD +target vector}. The set of functions which appear in a particular +target vector is often referred to as a BFD backend. + +The third interface is a set of oddball functions which are typically +specific to a particular object file format, are not generic functions, +and are called from outside of the BFD library. These are used as hooks +by the linker and the assembler when a particular object file format +requires some action which the BFD generic interface does not provide. +These functions are typically declared in @file{bfd.h}, but in many +cases they are only provided when BFD is configured with support for a +particular object file format. These functions live in a grey area, and +are not really part of the official BFD interface. + +The fourth interface is the set of BFD support functions which are +called by the other BFD functions. These manage issues like memory +allocation, error handling, file access, hash tables, swapping, and the +like. These functions are never called from outside of the BFD library. + +@node BFD library users +@subsection BFD library users + +Another way to look at the BFD library is to divide it into three parts +by the manner in which it is used. + +The first use is to read an object file. The object file readers are +programs like @samp{gdb}, @samp{nm}, @samp{objdump}, and @samp{objcopy}. +These programs use BFD to view an object file in a generic form. The +official BFD interface is normally fully adequate for these programs. + +The second use is to write an object file. The object file writers are +programs like @samp{gas} and @samp{objcopy}. These programs use BFD to +create an object file. The official BFD interface is normally adequate +for these programs, but for some object file formats the assembler needs +some additional hooks in order to set particular flags or other +information. The official BFD interface includes functions to copy +private information from one object file to another, and these functions +are used by @samp{objcopy} to avoid information loss. + +The third use is to link object files. There is only one object file +linker, @samp{ld}. Originally, @samp{ld} was an object file reader and +an object file writer, and it did the link operation using the generic +BFD structures. However, this turned out to be too slow and too memory +intensive. + +The official BFD linker functions were written to permit specific BFD +backends to perform the link without translating through the generic +structures, in the normal case where all the input files and output file +have the same object file format. Not all of the backends currently +implement the new interface, and there are default linking functions +within BFD which use the generic structures and which work with all +backends. + +For several object file formats the linker needs additional hooks which +are not provided by the official BFD interface, particularly for dynamic +linking support. These functions are typically called from the linker +emulation template. + +@node BFD view +@subsection The BFD view of a file + +BFD uses generic structures to manage information. It translates data +into the generic form when reading files, and out of the generic form +when writing files. + +BFD describes a file as a pointer to the @samp{bfd} type. A @samp{bfd} +is composed of the following elements. The BFD information can be +displayed using the @samp{objdump} program with various options. + +@table @asis +@item general information +The object file format, a few general flags, the start address. +@item architecture +The architecture, including both a general processor type (m68k, MIPS +etc.) and a specific machine number (m68000, R4000, etc.). +@item sections +A list of sections. +@item symbols +A symbol table. +@end table + +BFD represents a section as a pointer to the @samp{asection} type. Each +section has a name and a size. Most sections also have an associated +block of data, known as the section contents. Sections also have +associated flags, a virtual memory address, a load memory address, a +required alignment, a list of relocations, and other miscellaneous +information. + +BFD represents a relocation as a pointer to the @samp{arelent} type. A +relocation describes an action which the linker must take to modify the +section contents. Relocations have a symbol, an address, an addend, and +a pointer to a howto structure which describes how to perform the +relocation. For more information, see @ref{BFD relocation handling}. + +BFD represents a symbol as a pointer to the @samp{asymbol} type. A +symbol has a name, a pointer to a section, an offset within that +section, and some flags. + +Archive files do not have any sections or symbols. Instead, BFD +represents an archive file as a file which contains a list of +@samp{bfd}s. BFD also provides access to the archive symbol map, as a +list of symbol names. BFD provides a function to return the @samp{bfd} +within the archive which corresponds to a particular entry in the +archive symbol map. + +@node BFD blindness +@subsection BFD loses information + +Most object file formats have information which BFD can not represent in +its generic form, at least as currently defined. + +There is often explicit information which BFD can not represent. For +example, the COFF version stamp, or the ELF program segments. BFD +provides special hooks to handle this information when copying, +printing, or linking an object file. The BFD support for a particular +object file format will normally store this information in private data +and handle it using the special hooks. + +In some cases there is also implicit information which BFD can not +represent. For example, the MIPS processor distinguishes small and +large symbols, and requires that all small symbls be within 32K of the +GP register. This means that the MIPS assembler must be able to mark +variables as either small or large, and the MIPS linker must know to put +small symbols within range of the GP register. Since BFD can not +represent this information, this means that the assembler and linker +must have information that is specific to a particular object file +format which is outside of the BFD library. + +This loss of information indicates areas where the BFD paradigm breaks +down. It is not actually possible to represent the myriad differences +among object file formats using a single generic interface, at least not +in the manner which BFD does it today. + +Nevertheless, the BFD library does greatly simplify the task of dealing +with object files, and particular problems caused by information loss +can normally be solved using some sort of relatively constrained hook +into the library. + + + +@node BFD guidelines +@section BFD programming guidelines +@cindex bfd programming guidelines +@cindex programming guidelines for bfd +@cindex guidelines, bfd programming + +There is a lot of poorly written and confusing code in BFD. New BFD +code should be written to a higher standard. Merely because some BFD +code is written in a particular manner does not mean that you should +emulate it. + +Here are some general BFD programming guidelines: + +@itemize @bullet +@item +Follow the GNU coding standards. + +@item +Avoid global variables. We ideally want BFD to be fully reentrant, so +that it can be used in multiple threads. All uses of global or static +variables interfere with that. Initialized constant variables are OK, +and they should be explicitly marked with const. Instead of global +variables, use data attached to a BFD or to a linker hash table. + +@item +All externally visible functions should have names which start with +@samp{bfd_}. All such functions should be declared in some header file, +typically @file{bfd.h}. See, for example, the various declarations near +the end of @file{bfd-in.h}, which mostly declare functions required by +specific linker emulations. + +@item +All functions which need to be visible from one file to another within +BFD, but should not be visible outside of BFD, should start with +@samp{_bfd_}. Although external names beginning with @samp{_} are +prohibited by the ANSI standard, in practice this usage will always +work, and it is required by the GNU coding standards. + +@item +Always remember that people can compile using @samp{--enable-targets} to +build several, or all, targets at once. It must be possible to link +together the files for all targets. + +@item +BFD code should compile with few or no warnings using @samp{gcc -Wall}. +Some warnings are OK, like the absence of certain function declarations +which may or may not be declared in system header files. Warnings about +ambiguous expressions and the like should always be fixed. +@end itemize + +@node BFD target vector +@section BFD target vector +@cindex bfd target vector +@cindex target vector in bfd + +BFD supports multiple object file formats by using the @dfn{target +vector}. This is simply a set of function pointers which implement +behaviour that is specific to a particular object file format. + +In this section I list all of the entries in the target vector and +describe what they do. + +@menu +* BFD target vector miscellaneous:: Miscellaneous constants +* BFD target vector swap:: Swapping functions +* BFD target vector format:: Format type dependent functions +* BFD_JUMP_TABLE macros:: BFD_JUMP_TABLE macros +* BFD target vector generic:: Generic functions +* BFD target vector copy:: Copy functions +* BFD target vector core:: Core file support functions +* BFD target vector archive:: Archive functions +* BFD target vector symbols:: Symbol table functions +* BFD target vector relocs:: Relocation support +* BFD target vector write:: Output functions +* BFD target vector link:: Linker functions +* BFD target vector dynamic:: Dynamic linking information functions +@end menu + +@node BFD target vector miscellaneous +@subsection Miscellaneous constants + +The target vector starts with a set of constants. + +@table @samp +@item name +The name of the target vector. This is an arbitrary string. This is +how the target vector is named in command line options for tools which +use BFD, such as the @samp{--oformat} linker option. + +@item flavour +A general description of the type of target. The following flavours are +currently defined: + +@table @samp +@item bfd_target_unknown_flavour +Undefined or unknown. +@item bfd_target_aout_flavour +a.out. +@item bfd_target_coff_flavour +COFF. +@item bfd_target_ecoff_flavour +ECOFF. +@item bfd_target_elf_flavour +ELF. +@item bfd_target_ieee_flavour +IEEE-695. +@item bfd_target_nlm_flavour +NLM. +@item bfd_target_oasys_flavour +OASYS. +@item bfd_target_tekhex_flavour +Tektronix hex format. +@item bfd_target_srec_flavour +Motorola S-record format. +@item bfd_target_ihex_flavour +Intel hex format. +@item bfd_target_som_flavour +SOM (used on HP/UX). +@item bfd_target_os9k_flavour +os9000. +@item bfd_target_versados_flavour +VERSAdos. +@item bfd_target_msdos_flavour +MS-DOS. +@item bfd_target_evax_flavour +openVMS. +@item bfd_target_mmo_flavour +Donald Knuth's MMIXware object format. +@end table + +@item byteorder +The byte order of data in the object file. One of +@samp{BFD_ENDIAN_BIG}, @samp{BFD_ENDIAN_LITTLE}, or +@samp{BFD_ENDIAN_UNKNOWN}. The latter would be used for a format such +as S-records which do not record the architecture of the data. + +@item header_byteorder +The byte order of header information in the object file. Normally the +same as the @samp{byteorder} field, but there are certain cases where it +may be different. + +@item object_flags +Flags which may appear in the @samp{flags} field of a BFD with this +format. + +@item section_flags +Flags which may appear in the @samp{flags} field of a section within a +BFD with this format. + +@item symbol_leading_char +A character which the C compiler normally puts before a symbol. For +example, an a.out compiler will typically generate the symbol +@samp{_foo} for a function named @samp{foo} in the C source, in which +case this field would be @samp{_}. If there is no such character, this +field will be @samp{0}. + +@item ar_pad_char +The padding character to use at the end of an archive name. Normally +@samp{/}. + +@item ar_max_namelen +The maximum length of a short name in an archive. Normally @samp{14}. + +@item backend_data +A pointer to constant backend data. This is used by backends to store +whatever additional information they need to distinguish similar target +vectors which use the same sets of functions. +@end table + +@node BFD target vector swap +@subsection Swapping functions + +Every target vector has function pointers used for swapping information +in and out of the target representation. There are two sets of +functions: one for data information, and one for header information. +Each set has three sizes: 64-bit, 32-bit, and 16-bit. Each size has +three actual functions: put, get unsigned, and get signed. + +These 18 functions are used to convert data between the host and target +representations. + +@node BFD target vector format +@subsection Format type dependent functions + +Every target vector has three arrays of function pointers which are +indexed by the BFD format type. The BFD format types are as follows: + +@table @samp +@item bfd_unknown +Unknown format. Not used for anything useful. +@item bfd_object +Object file. +@item bfd_archive +Archive file. +@item bfd_core +Core file. +@end table + +The three arrays of function pointers are as follows: + +@table @samp +@item bfd_check_format +Check whether the BFD is of a particular format (object file, archive +file, or core file) corresponding to this target vector. This is called +by the @samp{bfd_check_format} function when examining an existing BFD. +If the BFD matches the desired format, this function will initialize any +format specific information such as the @samp{tdata} field of the BFD. +This function must be called before any other BFD target vector function +on a file opened for reading. + +@item bfd_set_format +Set the format of a BFD which was created for output. This is called by +the @samp{bfd_set_format} function after creating the BFD with a +function such as @samp{bfd_openw}. This function will initialize format +specific information required to write out an object file or whatever of +the given format. This function must be called before any other BFD +target vector function on a file opened for writing. + +@item bfd_write_contents +Write out the contents of the BFD in the given format. This is called +by @samp{bfd_close} function for a BFD opened for writing. This really +should not be an array selected by format type, as the +@samp{bfd_set_format} function provides all the required information. +In fact, BFD will fail if a different format is used when calling +through the @samp{bfd_set_format} and the @samp{bfd_write_contents} +arrays; fortunately, since @samp{bfd_close} gets it right, this is a +difficult error to make. +@end table + +@node BFD_JUMP_TABLE macros +@subsection @samp{BFD_JUMP_TABLE} macros +@cindex @samp{BFD_JUMP_TABLE} + +Most target vectors are defined using @samp{BFD_JUMP_TABLE} macros. +These macros take a single argument, which is a prefix applied to a set +of functions. The macros are then used to initialize the fields in the +target vector. + +For example, the @samp{BFD_JUMP_TABLE_RELOCS} macro defines three +functions: @samp{_get_reloc_upper_bound}, @samp{_canonicalize_reloc}, +and @samp{_bfd_reloc_type_lookup}. A reference like +@samp{BFD_JUMP_TABLE_RELOCS (foo)} will expand into three functions +prefixed with @samp{foo}: @samp{foo_get_reloc_upper_bound}, etc. The +@samp{BFD_JUMP_TABLE_RELOCS} macro will be placed such that those three +functions initialize the appropriate fields in the BFD target vector. + +This is done because it turns out that many different target vectors can +share certain classes of functions. For example, archives are similar +on most platforms, so most target vectors can use the same archive +functions. Those target vectors all use @samp{BFD_JUMP_TABLE_ARCHIVE} +with the same argument, calling a set of functions which is defined in +@file{archive.c}. + +Each of the @samp{BFD_JUMP_TABLE} macros is mentioned below along with +the description of the function pointers which it defines. The function +pointers will be described using the name without the prefix which the +@samp{BFD_JUMP_TABLE} macro defines. This name is normally the same as +the name of the field in the target vector structure. Any differences +will be noted. + +@node BFD target vector generic +@subsection Generic functions +@cindex @samp{BFD_JUMP_TABLE_GENERIC} + +The @samp{BFD_JUMP_TABLE_GENERIC} macro is used for some catch all +functions which don't easily fit into other categories. + +@table @samp +@item _close_and_cleanup +Free any target specific information associated with the BFD. This is +called when any BFD is closed (the @samp{bfd_write_contents} function +mentioned earlier is only called for a BFD opened for writing). Most +targets use @samp{bfd_alloc} to allocate all target specific +information, and therefore don't have to do anything in this function. +This function pointer is typically set to +@samp{_bfd_generic_close_and_cleanup}, which simply returns true. + +@item _bfd_free_cached_info +Free any cached information associated with the BFD which can be +recreated later if necessary. This is used to reduce the memory +consumption required by programs using BFD. This is normally called via +the @samp{bfd_free_cached_info} macro. It is used by the default +archive routines when computing the archive map. Most targets do not +do anything special for this entry point, and just set it to +@samp{_bfd_generic_free_cached_info}, which simply returns true. + +@item _new_section_hook +This is called from @samp{bfd_make_section_anyway} whenever a new +section is created. Most targets use it to initialize section specific +information. This function is called whether or not the section +corresponds to an actual section in an actual BFD. + +@item _get_section_contents +Get the contents of a section. This is called from +@samp{bfd_get_section_contents}. Most targets set this to +@samp{_bfd_generic_get_section_contents}, which does a @samp{bfd_seek} +based on the section's @samp{filepos} field and a @samp{bfd_bread}. The +corresponding field in the target vector is named +@samp{_bfd_get_section_contents}. + +@item _get_section_contents_in_window +Set a @samp{bfd_window} to hold the contents of a section. This is +called from @samp{bfd_get_section_contents_in_window}. The +@samp{bfd_window} idea never really caught on, and I don't think this is +ever called. Pretty much all targets implement this as +@samp{bfd_generic_get_section_contents_in_window}, which uses +@samp{bfd_get_section_contents} to do the right thing. The +corresponding field in the target vector is named +@samp{_bfd_get_section_contents_in_window}. +@end table + +@node BFD target vector copy +@subsection Copy functions +@cindex @samp{BFD_JUMP_TABLE_COPY} + +The @samp{BFD_JUMP_TABLE_COPY} macro is used for functions which are +called when copying BFDs, and for a couple of functions which deal with +internal BFD information. + +@table @samp +@item _bfd_copy_private_bfd_data +This is called when copying a BFD, via @samp{bfd_copy_private_bfd_data}. +If the input and output BFDs have the same format, this will copy any +private information over. This is called after all the section contents +have been written to the output file. Only a few targets do anything in +this function. + +@item _bfd_merge_private_bfd_data +This is called when linking, via @samp{bfd_merge_private_bfd_data}. It +gives the backend linker code a chance to set any special flags in the +output file based on the contents of the input file. Only a few targets +do anything in this function. + +@item _bfd_copy_private_section_data +This is similar to @samp{_bfd_copy_private_bfd_data}, but it is called +for each section, via @samp{bfd_copy_private_section_data}. This +function is called before any section contents have been written. Only +a few targets do anything in this function. + +@item _bfd_copy_private_symbol_data +This is called via @samp{bfd_copy_private_symbol_data}, but I don't +think anything actually calls it. If it were defined, it could be used +to copy private symbol data from one BFD to another. However, most BFDs +store extra symbol information by allocating space which is larger than +the @samp{asymbol} structure and storing private information in the +extra space. Since @samp{objcopy} and other programs copy symbol +information by copying pointers to @samp{asymbol} structures, the +private symbol information is automatically copied as well. Most +targets do not do anything in this function. + +@item _bfd_set_private_flags +This is called via @samp{bfd_set_private_flags}. It is basically a hook +for the assembler to set magic information. For example, the PowerPC +ELF assembler uses it to set flags which appear in the e_flags field of +the ELF header. Most targets do not do anything in this function. + +@item _bfd_print_private_bfd_data +This is called by @samp{objdump} when the @samp{-p} option is used. It +is called via @samp{bfd_print_private_data}. It prints any interesting +information about the BFD which can not be otherwise represented by BFD +and thus can not be printed by @samp{objdump}. Most targets do not do +anything in this function. +@end table + +@node BFD target vector core +@subsection Core file support functions +@cindex @samp{BFD_JUMP_TABLE_CORE} + +The @samp{BFD_JUMP_TABLE_CORE} macro is used for functions which deal +with core files. Obviously, these functions only do something +interesting for targets which have core file support. + +@table @samp +@item _core_file_failing_command +Given a core file, this returns the command which was run to produce the +core file. + +@item _core_file_failing_signal +Given a core file, this returns the signal number which produced the +core file. + +@item _core_file_matches_executable_p +Given a core file and a BFD for an executable, this returns whether the +core file was generated by the executable. +@end table + +@node BFD target vector archive +@subsection Archive functions +@cindex @samp{BFD_JUMP_TABLE_ARCHIVE} + +The @samp{BFD_JUMP_TABLE_ARCHIVE} macro is used for functions which deal +with archive files. Most targets use COFF style archive files +(including ELF targets), and these use @samp{_bfd_archive_coff} as the +argument to @samp{BFD_JUMP_TABLE_ARCHIVE}. Some targets use BSD/a.out +style archives, and these use @samp{_bfd_archive_bsd}. (The main +difference between BSD and COFF archives is the format of the archive +symbol table). Targets with no archive support use +@samp{_bfd_noarchive}. Finally, a few targets have unusual archive +handling. + +@table @samp +@item _slurp_armap +Read in the archive symbol table, storing it in private BFD data. This +is normally called from the archive @samp{check_format} routine. The +corresponding field in the target vector is named +@samp{_bfd_slurp_armap}. + +@item _slurp_extended_name_table +Read in the extended name table from the archive, if there is one, +storing it in private BFD data. This is normally called from the +archive @samp{check_format} routine. The corresponding field in the +target vector is named @samp{_bfd_slurp_extended_name_table}. + +@item construct_extended_name_table +Build and return an extended name table if one is needed to write out +the archive. This also adjusts the archive headers to refer to the +extended name table appropriately. This is normally called from the +archive @samp{write_contents} routine. The corresponding field in the +target vector is named @samp{_bfd_construct_extended_name_table}. + +@item _truncate_arname +This copies a file name into an archive header, truncating it as +required. It is normally called from the archive @samp{write_contents} +routine. This function is more interesting in targets which do not +support extended name tables, but I think the GNU @samp{ar} program +always uses extended name tables anyhow. The corresponding field in the +target vector is named @samp{_bfd_truncate_arname}. + +@item _write_armap +Write out the archive symbol table using calls to @samp{bfd_bwrite}. +This is normally called from the archive @samp{write_contents} routine. +The corresponding field in the target vector is named @samp{write_armap} +(no leading underscore). + +@item _read_ar_hdr +Read and parse an archive header. This handles expanding the archive +header name into the real file name using the extended name table. This +is called by routines which read the archive symbol table or the archive +itself. The corresponding field in the target vector is named +@samp{_bfd_read_ar_hdr_fn}. + +@item _openr_next_archived_file +Given an archive and a BFD representing a file stored within the +archive, return a BFD for the next file in the archive. This is called +via @samp{bfd_openr_next_archived_file}. The corresponding field in the +target vector is named @samp{openr_next_archived_file} (no leading +underscore). + +@item _get_elt_at_index +Given an archive and an index, return a BFD for the file in the archive +corresponding to that entry in the archive symbol table. This is called +via @samp{bfd_get_elt_at_index}. The corresponding field in the target +vector is named @samp{_bfd_get_elt_at_index}. + +@item _generic_stat_arch_elt +Do a stat on an element of an archive, returning information read from +the archive header (modification time, uid, gid, file mode, size). This +is called via @samp{bfd_stat_arch_elt}. The corresponding field in the +target vector is named @samp{_bfd_stat_arch_elt}. + +@item _update_armap_timestamp +After the entire contents of an archive have been written out, update +the timestamp of the archive symbol table to be newer than that of the +file. This is required for a.out style archives. This is normally +called by the archive @samp{write_contents} routine. The corresponding +field in the target vector is named @samp{_bfd_update_armap_timestamp}. +@end table + +@node BFD target vector symbols +@subsection Symbol table functions +@cindex @samp{BFD_JUMP_TABLE_SYMBOLS} + +The @samp{BFD_JUMP_TABLE_SYMBOLS} macro is used for functions which deal +with symbols. + +@table @samp +@item _get_symtab_upper_bound +Return a sensible upper bound on the amount of memory which will be +required to read the symbol table. In practice most targets return the +amount of memory required to hold @samp{asymbol} pointers for all the +symbols plus a trailing @samp{NULL} entry, and store the actual symbol +information in BFD private data. This is called via +@samp{bfd_get_symtab_upper_bound}. The corresponding field in the +target vector is named @samp{_bfd_get_symtab_upper_bound}. + +@item _canonicalize_symtab +Read in the symbol table. This is called via +@samp{bfd_canonicalize_symtab}. The corresponding field in the target +vector is named @samp{_bfd_canonicalize_symtab}. + +@item _make_empty_symbol +Create an empty symbol for the BFD. This is needed because most targets +store extra information with each symbol by allocating a structure +larger than an @samp{asymbol} and storing the extra information at the +end. This function will allocate the right amount of memory, and return +what looks like a pointer to an empty @samp{asymbol}. This is called +via @samp{bfd_make_empty_symbol}. The corresponding field in the target +vector is named @samp{_bfd_make_empty_symbol}. + +@item _print_symbol +Print information about the symbol. This is called via +@samp{bfd_print_symbol}. One of the arguments indicates what sort of +information should be printed: + +@table @samp +@item bfd_print_symbol_name +Just print the symbol name. +@item bfd_print_symbol_more +Print the symbol name and some interesting flags. I don't think +anything actually uses this. +@item bfd_print_symbol_all +Print all information about the symbol. This is used by @samp{objdump} +when run with the @samp{-t} option. +@end table +The corresponding field in the target vector is named +@samp{_bfd_print_symbol}. + +@item _get_symbol_info +Return a standard set of information about the symbol. This is called +via @samp{bfd_symbol_info}. The corresponding field in the target +vector is named @samp{_bfd_get_symbol_info}. + +@item _bfd_is_local_label_name +Return whether the given string would normally represent the name of a +local label. This is called via @samp{bfd_is_local_label} and +@samp{bfd_is_local_label_name}. Local labels are normally discarded by +the assembler. In the linker, this defines the difference between the +@samp{-x} and @samp{-X} options. + +@item _get_lineno +Return line number information for a symbol. This is only meaningful +for a COFF target. This is called when writing out COFF line numbers. + +@item _find_nearest_line +Given an address within a section, use the debugging information to find +the matching file name, function name, and line number, if any. This is +called via @samp{bfd_find_nearest_line}. The corresponding field in the +target vector is named @samp{_bfd_find_nearest_line}. + +@item _bfd_make_debug_symbol +Make a debugging symbol. This is only meaningful for a COFF target, +where it simply returns a symbol which will be placed in the +@samp{N_DEBUG} section when it is written out. This is called via +@samp{bfd_make_debug_symbol}. + +@item _read_minisymbols +Minisymbols are used to reduce the memory requirements of programs like +@samp{nm}. A minisymbol is a cookie pointing to internal symbol +information which the caller can use to extract complete symbol +information. This permits BFD to not convert all the symbols into +generic form, but to instead convert them one at a time. This is called +via @samp{bfd_read_minisymbols}. Most targets do not implement this, +and just use generic support which is based on using standard +@samp{asymbol} structures. + +@item _minisymbol_to_symbol +Convert a minisymbol to a standard @samp{asymbol}. This is called via +@samp{bfd_minisymbol_to_symbol}. +@end table + +@node BFD target vector relocs +@subsection Relocation support +@cindex @samp{BFD_JUMP_TABLE_RELOCS} + +The @samp{BFD_JUMP_TABLE_RELOCS} macro is used for functions which deal +with relocations. + +@table @samp +@item _get_reloc_upper_bound +Return a sensible upper bound on the amount of memory which will be +required to read the relocations for a section. In practice most +targets return the amount of memory required to hold @samp{arelent} +pointers for all the relocations plus a trailing @samp{NULL} entry, and +store the actual relocation information in BFD private data. This is +called via @samp{bfd_get_reloc_upper_bound}. + +@item _canonicalize_reloc +Return the relocation information for a section. This is called via +@samp{bfd_canonicalize_reloc}. The corresponding field in the target +vector is named @samp{_bfd_canonicalize_reloc}. + +@item _bfd_reloc_type_lookup +Given a relocation code, return the corresponding howto structure +(@pxref{BFD relocation codes}). This is called via +@samp{bfd_reloc_type_lookup}. The corresponding field in the target +vector is named @samp{reloc_type_lookup}. +@end table + +@node BFD target vector write +@subsection Output functions +@cindex @samp{BFD_JUMP_TABLE_WRITE} + +The @samp{BFD_JUMP_TABLE_WRITE} macro is used for functions which deal +with writing out a BFD. + +@table @samp +@item _set_arch_mach +Set the architecture and machine number for a BFD. This is called via +@samp{bfd_set_arch_mach}. Most targets implement this by calling +@samp{bfd_default_set_arch_mach}. The corresponding field in the target +vector is named @samp{_bfd_set_arch_mach}. + +@item _set_section_contents +Write out the contents of a section. This is called via +@samp{bfd_set_section_contents}. The corresponding field in the target +vector is named @samp{_bfd_set_section_contents}. +@end table + +@node BFD target vector link +@subsection Linker functions +@cindex @samp{BFD_JUMP_TABLE_LINK} + +The @samp{BFD_JUMP_TABLE_LINK} macro is used for functions called by the +linker. + +@table @samp +@item _sizeof_headers +Return the size of the header information required for a BFD. This is +used to implement the @samp{SIZEOF_HEADERS} linker script function. It +is normally used to align the first section at an efficient position on +the page. This is called via @samp{bfd_sizeof_headers}. The +corresponding field in the target vector is named +@samp{_bfd_sizeof_headers}. + +@item _bfd_get_relocated_section_contents +Read the contents of a section and apply the relocation information. +This handles both a final link and a relocatable link; in the latter +case, it adjust the relocation information as well. This is called via +@samp{bfd_get_relocated_section_contents}. Most targets implement it by +calling @samp{bfd_generic_get_relocated_section_contents}. + +@item _bfd_relax_section +Try to use relaxation to shrink the size of a section. This is called +by the linker when the @samp{-relax} option is used. This is called via +@samp{bfd_relax_section}. Most targets do not support any sort of +relaxation. + +@item _bfd_link_hash_table_create +Create the symbol hash table to use for the linker. This linker hook +permits the backend to control the size and information of the elements +in the linker symbol hash table. This is called via +@samp{bfd_link_hash_table_create}. + +@item _bfd_link_add_symbols +Given an object file or an archive, add all symbols into the linker +symbol hash table. Use callbacks to the linker to include archive +elements in the link. This is called via @samp{bfd_link_add_symbols}. + +@item _bfd_final_link +Finish the linking process. The linker calls this hook after all of the +input files have been read, when it is ready to finish the link and +generate the output file. This is called via @samp{bfd_final_link}. + +@item _bfd_link_split_section +I don't know what this is for. Nothing seems to call it. The only +non-trivial definition is in @file{som.c}. +@end table + +@node BFD target vector dynamic +@subsection Dynamic linking information functions +@cindex @samp{BFD_JUMP_TABLE_DYNAMIC} + +The @samp{BFD_JUMP_TABLE_DYNAMIC} macro is used for functions which read +dynamic linking information. + +@table @samp +@item _get_dynamic_symtab_upper_bound +Return a sensible upper bound on the amount of memory which will be +required to read the dynamic symbol table. In practice most targets +return the amount of memory required to hold @samp{asymbol} pointers for +all the symbols plus a trailing @samp{NULL} entry, and store the actual +symbol information in BFD private data. This is called via +@samp{bfd_get_dynamic_symtab_upper_bound}. The corresponding field in +the target vector is named @samp{_bfd_get_dynamic_symtab_upper_bound}. + +@item _canonicalize_dynamic_symtab +Read the dynamic symbol table. This is called via +@samp{bfd_canonicalize_dynamic_symtab}. The corresponding field in the +target vector is named @samp{_bfd_canonicalize_dynamic_symtab}. + +@item _get_dynamic_reloc_upper_bound +Return a sensible upper bound on the amount of memory which will be +required to read the dynamic relocations. In practice most targets +return the amount of memory required to hold @samp{arelent} pointers for +all the relocations plus a trailing @samp{NULL} entry, and store the +actual relocation information in BFD private data. This is called via +@samp{bfd_get_dynamic_reloc_upper_bound}. The corresponding field in +the target vector is named @samp{_bfd_get_dynamic_reloc_upper_bound}. + +@item _canonicalize_dynamic_reloc +Read the dynamic relocations. This is called via +@samp{bfd_canonicalize_dynamic_reloc}. The corresponding field in the +target vector is named @samp{_bfd_canonicalize_dynamic_reloc}. +@end table + +@node BFD generated files +@section BFD generated files +@cindex generated files in bfd +@cindex bfd generated files + +BFD contains several automatically generated files. This section +describes them. Some files are created at configure time, when you +configure BFD. Some files are created at make time, when you build +BFD. Some files are automatically rebuilt at make time, but only if +you configure with the @samp{--enable-maintainer-mode} option. Some +files live in the object directory---the directory from which you run +configure---and some live in the source directory. All files that live +in the source directory are checked into the CVS repository. + +@table @file +@item bfd.h +@cindex @file{bfd.h} +@cindex @file{bfd-in3.h} +Lives in the object directory. Created at make time from +@file{bfd-in2.h} via @file{bfd-in3.h}. @file{bfd-in3.h} is created at +configure time from @file{bfd-in2.h}. There are automatic dependencies +to rebuild @file{bfd-in3.h} and hence @file{bfd.h} if @file{bfd-in2.h} +changes, so you can normally ignore @file{bfd-in3.h}, and just think +about @file{bfd-in2.h} and @file{bfd.h}. + +@file{bfd.h} is built by replacing a few strings in @file{bfd-in2.h}. +To see them, search for @samp{@@} in @file{bfd-in2.h}. They mainly +control whether BFD is built for a 32 bit target or a 64 bit target. + +@item bfd-in2.h +@cindex @file{bfd-in2.h} +Lives in the source directory. Created from @file{bfd-in.h} and several +other BFD source files. If you configure with the +@samp{--enable-maintainer-mode} option, @file{bfd-in2.h} is rebuilt +automatically when a source file changes. + +@item elf32-target.h +@itemx elf64-target.h +@cindex @file{elf32-target.h} +@cindex @file{elf64-target.h} +Live in the object directory. Created from @file{elfxx-target.h}. +These files are versions of @file{elfxx-target.h} customized for either +a 32 bit ELF target or a 64 bit ELF target. + +@item libbfd.h +@cindex @file{libbfd.h} +Lives in the source directory. Created from @file{libbfd-in.h} and +several other BFD source files. If you configure with the +@samp{--enable-maintainer-mode} option, @file{libbfd.h} is rebuilt +automatically when a source file changes. + +@item libcoff.h +@cindex @file{libcoff.h} +Lives in the source directory. Created from @file{libcoff-in.h} and +@file{coffcode.h}. If you configure with the +@samp{--enable-maintainer-mode} option, @file{libcoff.h} is rebuilt +automatically when a source file changes. + +@item targmatch.h +@cindex @file{targmatch.h} +Lives in the object directory. Created at make time from +@file{config.bfd}. This file is used to map configuration triplets into +BFD target vector variable names at run time. +@end table + +@node BFD multiple compilations +@section Files compiled multiple times in BFD +Several files in BFD are compiled multiple times. By this I mean that +there are header files which contain function definitions. These header +files are included by other files, and thus the functions are compiled +once per file which includes them. + +Preprocessor macros are used to control the compilation, so that each +time the files are compiled the resulting functions are slightly +different. Naturally, if they weren't different, there would be no +reason to compile them multiple times. + +This is a not a particularly good programming technique, and future BFD +work should avoid it. + +@itemize @bullet +@item +Since this technique is rarely used, even experienced C programmers find +it confusing. + +@item +It is difficult to debug programs which use BFD, since there is no way +to describe which version of a particular function you are looking at. + +@item +Programs which use BFD wind up incorporating two or more slightly +different versions of the same function, which wastes space in the +executable. + +@item +This technique is never required nor is it especially efficient. It is +always possible to use statically initialized structures holding +function pointers and magic constants instead. +@end itemize + +The following is a list of the files which are compiled multiple times. + +@table @file +@item aout-target.h +@cindex @file{aout-target.h} +Describes a few functions and the target vector for a.out targets. This +is used by individual a.out targets with different definitions of +@samp{N_TXTADDR} and similar a.out macros. + +@item aoutf1.h +@cindex @file{aoutf1.h} +Implements standard SunOS a.out files. In principle it supports 64 bit +a.out targets based on the preprocessor macro @samp{ARCH_SIZE}, but +since all known a.out targets are 32 bits, this code may or may not +work. This file is only included by a few other files, and it is +difficult to justify its existence. + +@item aoutx.h +@cindex @file{aoutx.h} +Implements basic a.out support routines. This file can be compiled for +either 32 or 64 bit support. Since all known a.out targets are 32 bits, +the 64 bit support may or may not work. I believe the original +intention was that this file would only be included by @samp{aout32.c} +and @samp{aout64.c}, and that other a.out targets would simply refer to +the functions it defined. Unfortunately, some other a.out targets +started including it directly, leading to a somewhat confused state of +affairs. + +@item coffcode.h +@cindex @file{coffcode.h} +Implements basic COFF support routines. This file is included by every +COFF target. It implements code which handles COFF magic numbers as +well as various hook functions called by the generic COFF functions in +@file{coffgen.c}. This file is controlled by a number of different +macros, and more are added regularly. + +@item coffswap.h +@cindex @file{coffswap.h} +Implements COFF swapping routines. This file is included by +@file{coffcode.h}, and thus by every COFF target. It implements the +routines which swap COFF structures between internal and external +format. The main control for this file is the external structure +definitions in the files in the @file{include/coff} directory. A COFF +target file will include one of those files before including +@file{coffcode.h} and thus @file{coffswap.h}. There are a few other +macros which affect @file{coffswap.h} as well, mostly describing whether +certain fields are present in the external structures. + +@item ecoffswap.h +@cindex @file{ecoffswap.h} +Implements ECOFF swapping routines. This is like @file{coffswap.h}, but +for ECOFF. It is included by the ECOFF target files (of which there are +only two). The control is the preprocessor macro @samp{ECOFF_32} or +@samp{ECOFF_64}. + +@item elfcode.h +@cindex @file{elfcode.h} +Implements ELF functions that use external structure definitions. This +file is included by two other files: @file{elf32.c} and @file{elf64.c}. +It is controlled by the @samp{ARCH_SIZE} macro which is defined to be +@samp{32} or @samp{64} before including it. The @samp{NAME} macro is +used internally to give the functions different names for the two target +sizes. + +@item elfcore.h +@cindex @file{elfcore.h} +Like @file{elfcode.h}, but for functions that are specific to ELF core +files. This is included only by @file{elfcode.h}. + +@item elfxx-target.h +@cindex @file{elfxx-target.h} +This file is the source for the generated files @file{elf32-target.h} +and @file{elf64-target.h}, one of which is included by every ELF target. +It defines the ELF target vector. + +@item freebsd.h +@cindex @file{freebsd.h} +Presumably intended to be included by all FreeBSD targets, but in fact +there is only one such target, @samp{i386-freebsd}. This defines a +function used to set the right magic number for FreeBSD, as well as +various macros, and includes @file{aout-target.h}. + +@item netbsd.h +@cindex @file{netbsd.h} +Like @file{freebsd.h}, except that there are several files which include +it. + +@item nlm-target.h +@cindex @file{nlm-target.h} +Defines the target vector for a standard NLM target. + +@item nlmcode.h +@cindex @file{nlmcode.h} +Like @file{elfcode.h}, but for NLM targets. This is only included by +@file{nlm32.c} and @file{nlm64.c}, both of which define the macro +@samp{ARCH_SIZE} to an appropriate value. There are no 64 bit NLM +targets anyhow, so this is sort of useless. + +@item nlmswap.h +@cindex @file{nlmswap.h} +Like @file{coffswap.h}, but for NLM targets. This is included by each +NLM target, but I think it winds up compiling to the exact same code for +every target, and as such is fairly useless. + +@item peicode.h +@cindex @file{peicode.h} +Provides swapping routines and other hooks for PE targets. +@file{coffcode.h} will include this rather than @file{coffswap.h} for a +PE target. This defines PE specific versions of the COFF swapping +routines, and also defines some macros which control @file{coffcode.h} +itself. +@end table + +@node BFD relocation handling +@section BFD relocation handling +@cindex bfd relocation handling +@cindex relocations in bfd + +The handling of relocations is one of the more confusing aspects of BFD. +Relocation handling has been implemented in various different ways, all +somewhat incompatible, none perfect. + +@menu +* BFD relocation concepts:: BFD relocation concepts +* BFD relocation functions:: BFD relocation functions +* BFD relocation codes:: BFD relocation codes +* BFD relocation future:: BFD relocation future +@end menu + +@node BFD relocation concepts +@subsection BFD relocation concepts + +A relocation is an action which the linker must take when linking. It +describes a change to the contents of a section. The change is normally +based on the final value of one or more symbols. Relocations are +created by the assembler when it creates an object file. + +Most relocations are simple. A typical simple relocation is to set 32 +bits at a given offset in a section to the value of a symbol. This type +of relocation would be generated for code like @code{int *p = &i;} where +@samp{p} and @samp{i} are global variables. A relocation for the symbol +@samp{i} would be generated such that the linker would initialize the +area of memory which holds the value of @samp{p} to the value of the +symbol @samp{i}. + +Slightly more complex relocations may include an addend, which is a +constant to add to the symbol value before using it. In some cases a +relocation will require adding the symbol value to the existing contents +of the section in the object file. In others the relocation will simply +replace the contents of the section with the symbol value. Some +relocations are PC relative, so that the value to be stored in the +section is the difference between the value of a symbol and the final +address of the section contents. + +In general, relocations can be arbitrarily complex. For example, +relocations used in dynamic linking systems often require the linker to +allocate space in a different section and use the offset within that +section as the value to store. In the IEEE object file format, +relocations may involve arbitrary expressions. + +When doing a relocatable link, the linker may or may not have to do +anything with a relocation, depending upon the definition of the +relocation. Simple relocations generally do not require any special +action. + +@node BFD relocation functions +@subsection BFD relocation functions + +In BFD, each section has an array of @samp{arelent} structures. Each +structure has a pointer to a symbol, an address within the section, an +addend, and a pointer to a @samp{reloc_howto_struct} structure. The +howto structure has a bunch of fields describing the reloc, including a +type field. The type field is specific to the object file format +backend; none of the generic code in BFD examines it. + +Originally, the function @samp{bfd_perform_relocation} was supposed to +handle all relocations. In theory, many relocations would be simple +enough to be described by the fields in the howto structure. For those +that weren't, the howto structure included a @samp{special_function} +field to use as an escape. + +While this seems plausible, a look at @samp{bfd_perform_relocation} +shows that it failed. The function has odd special cases. Some of the +fields in the howto structure, such as @samp{pcrel_offset}, were not +adequately documented. + +The linker uses @samp{bfd_perform_relocation} to do all relocations when +the input and output file have different formats (e.g., when generating +S-records). The generic linker code, which is used by all targets which +do not define their own special purpose linker, uses +@samp{bfd_get_relocated_section_contents}, which for most targets turns +into a call to @samp{bfd_generic_get_relocated_section_contents}, which +calls @samp{bfd_perform_relocation}. So @samp{bfd_perform_relocation} +is still widely used, which makes it difficult to change, since it is +difficult to test all possible cases. + +The assembler used @samp{bfd_perform_relocation} for a while. This +turned out to be the wrong thing to do, since +@samp{bfd_perform_relocation} was written to handle relocations on an +existing object file, while the assembler needed to create relocations +in a new object file. The assembler was changed to use the new function +@samp{bfd_install_relocation} instead, and @samp{bfd_install_relocation} +was created as a copy of @samp{bfd_perform_relocation}. + +Unfortunately, the work did not progress any farther, so +@samp{bfd_install_relocation} remains a simple copy of +@samp{bfd_perform_relocation}, with all the odd special cases and +confusing code. This again is difficult to change, because again any +change can affect any assembler target, and so is difficult to test. + +The new linker, when using the same object file format for all input +files and the output file, does not convert relocations into +@samp{arelent} structures, so it can not use +@samp{bfd_perform_relocation} at all. Instead, users of the new linker +are expected to write a @samp{relocate_section} function which will +handle relocations in a target specific fashion. + +There are two helper functions for target specific relocation: +@samp{_bfd_final_link_relocate} and @samp{_bfd_relocate_contents}. +These functions use a howto structure, but they @emph{do not} use the +@samp{special_function} field. Since the functions are normally called +from target specific code, the @samp{special_function} field adds +little; any relocations which require special handling can be handled +without calling those functions. + +So, if you want to add a new target, or add a new relocation to an +existing target, you need to do the following: + +@itemize @bullet +@item +Make sure you clearly understand what the contents of the section should +look like after assembly, after a relocatable link, and after a final +link. Make sure you clearly understand the operations the linker must +perform during a relocatable link and during a final link. + +@item +Write a howto structure for the relocation. The howto structure is +flexible enough to represent any relocation which should be handled by +setting a contiguous bitfield in the destination to the value of a +symbol, possibly with an addend, possibly adding the symbol value to the +value already present in the destination. + +@item +Change the assembler to generate your relocation. The assembler will +call @samp{bfd_install_relocation}, so your howto structure has to be +able to handle that. You may need to set the @samp{special_function} +field to handle assembly correctly. Be careful to ensure that any code +you write to handle the assembler will also work correctly when doing a +relocatable link. For example, see @samp{bfd_elf_generic_reloc}. + +@item +Test the assembler. Consider the cases of relocation against an +undefined symbol, a common symbol, a symbol defined in the object file +in the same section, and a symbol defined in the object file in a +different section. These cases may not all be applicable for your +reloc. + +@item +If your target uses the new linker, which is recommended, add any +required handling to the target specific relocation function. In simple +cases this will just involve a call to @samp{_bfd_final_link_relocate} +or @samp{_bfd_relocate_contents}, depending upon the definition of the +relocation and whether the link is relocatable or not. + +@item +Test the linker. Test the case of a final link. If the relocation can +overflow, use a linker script to force an overflow and make sure the +error is reported correctly. Test a relocatable link, whether the +symbol is defined or undefined in the relocatable output. For both the +final and relocatable link, test the case when the symbol is a common +symbol, when the symbol looked like a common symbol but became a defined +symbol, when the symbol is defined in a different object file, and when +the symbol is defined in the same object file. + +@item +In order for linking to another object file format, such as S-records, +to work correctly, @samp{bfd_perform_relocation} has to do the right +thing for the relocation. You may need to set the +@samp{special_function} field to handle this correctly. Test this by +doing a link in which the output object file format is S-records. + +@item +Using the linker to generate relocatable output in a different object +file format is impossible in the general case, so you generally don't +have to worry about that. The GNU linker makes sure to stop that from +happening when an input file in a different format has relocations. + +Linking input files of different object file formats together is quite +unusual, but if you're really dedicated you may want to consider testing +this case, both when the output object file format is the same as your +format, and when it is different. +@end itemize + +@node BFD relocation codes +@subsection BFD relocation codes + +BFD has another way of describing relocations besides the howto +structures described above: the enum @samp{bfd_reloc_code_real_type}. + +Every known relocation type can be described as a value in this +enumeration. The enumeration contains many target specific relocations, +but where two or more targets have the same relocation, a single code is +used. For example, the single value @samp{BFD_RELOC_32} is used for all +simple 32 bit relocation types. + +The main purpose of this relocation code is to give the assembler some +mechanism to create @samp{arelent} structures. In order for the +assembler to create an @samp{arelent} structure, it has to be able to +obtain a howto structure. The function @samp{bfd_reloc_type_lookup}, +which simply calls the target vector entry point +@samp{reloc_type_lookup}, takes a relocation code and returns a howto +structure. + +The function @samp{bfd_get_reloc_code_name} returns the name of a +relocation code. This is mainly used in error messages. + +Using both howto structures and relocation codes can be somewhat +confusing. There are many processor specific relocation codes. +However, the relocation is only fully defined by the howto structure. +The same relocation code will map to different howto structures in +different object file formats. For example, the addend handling may be +different. + +Most of the relocation codes are not really general. The assembler can +not use them without already understanding what sorts of relocations can +be used for a particular target. It might be possible to replace the +relocation codes with something simpler. + +@node BFD relocation future +@subsection BFD relocation future + +Clearly the current BFD relocation support is in bad shape. A +wholescale rewrite would be very difficult, because it would require +thorough testing of every BFD target. So some sort of incremental +change is required. + +My vague thoughts on this would involve defining a new, clearly defined, +howto structure. Some mechanism would be used to determine which type +of howto structure was being used by a particular format. + +The new howto structure would clearly define the relocation behaviour in +the case of an assembly, a relocatable link, and a final link. At +least one special function would be defined as an escape, and it might +make sense to define more. + +One or more generic functions similar to @samp{bfd_perform_relocation} +would be written to handle the new howto structure. + +This should make it possible to write a generic version of the relocate +section functions used by the new linker. The target specific code +would provide some mechanism (a function pointer or an initial +conversion) to convert target specific relocations into howto +structures. + +Ideally it would be possible to use this generic relocate section +function for the generic linker as well. That is, it would replace the +@samp{bfd_generic_get_relocated_section_contents} function which is +currently normally used. + +For the special case of ELF dynamic linking, more consideration needs to +be given to writing ELF specific but ELF target generic code to handle +special relocation types such as GOT and PLT. + +@node BFD ELF support +@section BFD ELF support +@cindex elf support in bfd +@cindex bfd elf support + +The ELF object file format is defined in two parts: a generic ABI and a +processor specific supplement. The ELF support in BFD is split in a +similar fashion. The processor specific support is largely kept within +a single file. The generic support is provided by several other files. +The processor specific support provides a set of function pointers and +constants used by the generic support. + +@menu +* BFD ELF sections and segments:: ELF sections and segments +* BFD ELF generic support:: BFD ELF generic support +* BFD ELF processor specific support:: BFD ELF processor specific support +* BFD ELF core files:: BFD ELF core files +* BFD ELF future:: BFD ELF future +@end menu + +@node BFD ELF sections and segments +@subsection ELF sections and segments + +The ELF ABI permits a file to have either sections or segments or both. +Relocateable object files conventionally have only sections. +Executables conventionally have both. Core files conventionally have +only program segments. + +ELF sections are similar to sections in other object file formats: they +have a name, a VMA, file contents, flags, and other miscellaneous +information. ELF relocations are stored in sections of a particular +type; BFD automatically converts these sections into internal relocation +information. + +ELF program segments are intended for fast interpretation by a system +loader. They have a type, a VMA, an LMA, file contents, and a couple of +other fields. When an ELF executable is run on a Unix system, the +system loader will examine the program segments to decide how to load +it. The loader will ignore the section information. Loadable program +segments (type @samp{PT_LOAD}) are directly loaded into memory. Other +program segments are interpreted by the loader, and generally provide +dynamic linking information. + +When an ELF file has both program segments and sections, an ELF program +segment may encompass one or more ELF sections, in the sense that the +portion of the file which corresponds to the program segment may include +the portions of the file corresponding to one or more sections. When +there is more than one section in a loadable program segment, the +relative positions of the section contents in the file must correspond +to the relative positions they should hold when the program segment is +loaded. This requirement should be obvious if you consider that the +system loader will load an entire program segment at a time. + +On a system which supports dynamic paging, such as any native Unix +system, the contents of a loadable program segment must be at the same +offset in the file as in memory, modulo the memory page size used on the +system. This is because the system loader will map the file into memory +starting at the start of a page. The system loader can easily remap +entire pages to the correct load address. However, if the contents of +the file were not correctly aligned within the page, the system loader +would have to shift the contents around within the page, which is too +expensive. For example, if the LMA of a loadable program segment is +@samp{0x40080} and the page size is @samp{0x1000}, then the position of +the segment contents within the file must equal @samp{0x80} modulo +@samp{0x1000}. + +BFD has only a single set of sections. It does not provide any generic +way to examine both sections and segments. When BFD is used to open an +object file or executable, the BFD sections will represent ELF sections. +When BFD is used to open a core file, the BFD sections will represent +ELF program segments. + +When BFD is used to examine an object file or executable, any program +segments will be read to set the LMA of the sections. This is because +ELF sections only have a VMA, while ELF program segments have both a VMA +and an LMA. Any program segments will be copied by the +@samp{copy_private} entry points. They will be printed by the +@samp{print_private} entry point. Otherwise, the program segments are +ignored. In particular, programs which use BFD currently have no direct +access to the program segments. + +When BFD is used to create an executable, the program segments will be +created automatically based on the section information. This is done in +the function @samp{assign_file_positions_for_segments} in @file{elf.c}. +This function has been tweaked many times, and probably still has +problems that arise in particular cases. + +There is a hook which may be used to explicitly define the program +segments when creating an executable: the @samp{bfd_record_phdr} +function in @file{bfd.c}. If this function is called, BFD will not +create program segments itself, but will only create the program +segments specified by the caller. The linker uses this function to +implement the @samp{PHDRS} linker script command. + +@node BFD ELF generic support +@subsection BFD ELF generic support + +In general, functions which do not read external data from the ELF file +are found in @file{elf.c}. They operate on the internal forms of the +ELF structures, which are defined in @file{include/elf/internal.h}. The +internal structures are defined in terms of @samp{bfd_vma}, and so may +be used for both 32 bit and 64 bit ELF targets. + +The file @file{elfcode.h} contains functions which operate on the +external data. @file{elfcode.h} is compiled twice, once via +@file{elf32.c} with @samp{ARCH_SIZE} defined as @samp{32}, and once via +@file{elf64.c} with @samp{ARCH_SIZE} defined as @samp{64}. +@file{elfcode.h} includes functions to swap the ELF structures in and +out of external form, as well as a few more complex functions. + +Linker support is found in @file{elflink.c}. The +linker support is only used if the processor specific file defines +@samp{elf_backend_relocate_section}, which is required to relocate the +section contents. If that macro is not defined, the generic linker code +is used, and relocations are handled via @samp{bfd_perform_relocation}. + +The core file support is in @file{elfcore.h}, which is compiled twice, +for both 32 and 64 bit support. The more interesting cases of core file +support only work on a native system which has the @file{sys/procfs.h} +header file. Without that file, the core file support does little more +than read the ELF program segments as BFD sections. + +The BFD internal header file @file{elf-bfd.h} is used for communication +among these files and the processor specific files. + +The default entries for the BFD ELF target vector are found mainly in +@file{elf.c}. Some functions are found in @file{elfcode.h}. + +The processor specific files may override particular entries in the +target vector, but most do not, with one exception: the +@samp{bfd_reloc_type_lookup} entry point is always processor specific. + +@node BFD ELF processor specific support +@subsection BFD ELF processor specific support + +By convention, the processor specific support for a particular processor +will be found in @file{elf@var{nn}-@var{cpu}.c}, where @var{nn} is +either 32 or 64, and @var{cpu} is the name of the processor. + +@menu +* BFD ELF processor required:: Required processor specific support +* BFD ELF processor linker:: Processor specific linker support +* BFD ELF processor other:: Other processor specific support options +@end menu + +@node BFD ELF processor required +@subsubsection Required processor specific support + +When writing a @file{elf@var{nn}-@var{cpu}.c} file, you must do the +following: + +@itemize @bullet +@item +Define either @samp{TARGET_BIG_SYM} or @samp{TARGET_LITTLE_SYM}, or +both, to a unique C name to use for the target vector. This name should +appear in the list of target vectors in @file{targets.c}, and will also +have to appear in @file{config.bfd} and @file{configure.in}. Define +@samp{TARGET_BIG_SYM} for a big-endian processor, +@samp{TARGET_LITTLE_SYM} for a little-endian processor, and define both +for a bi-endian processor. +@item +Define either @samp{TARGET_BIG_NAME} or @samp{TARGET_LITTLE_NAME}, or +both, to a string used as the name of the target vector. This is the +name which a user of the BFD tool would use to specify the object file +format. It would normally appear in a linker emulation parameters +file. +@item +Define @samp{ELF_ARCH} to the BFD architecture (an element of the +@samp{bfd_architecture} enum, typically @samp{bfd_arch_@var{cpu}}). +@item +Define @samp{ELF_MACHINE_CODE} to the magic number which should appear +in the @samp{e_machine} field of the ELF header. As of this writing, +these magic numbers are assigned by Caldera; if you want to get a magic +number for a particular processor, try sending a note to +@email{registry@@caldera.com}. In the BFD sources, the magic numbers are +found in @file{include/elf/common.h}; they have names beginning with +@samp{EM_}. +@item +Define @samp{ELF_MAXPAGESIZE} to the maximum size of a virtual page in +memory. This can normally be found at the start of chapter 5 in the +processor specific supplement. For a processor which will only be used +in an embedded system, or which has no memory management hardware, this +can simply be @samp{1}. +@item +If the format should use @samp{Rel} rather than @samp{Rela} relocations, +define @samp{USE_REL}. This is normally defined in chapter 4 of the +processor specific supplement. + +In the absence of a supplement, it's easier to work with @samp{Rela} +relocations. @samp{Rela} relocations will require more space in object +files (but not in executables, except when using dynamic linking). +However, this is outweighed by the simplicity of addend handling when +using @samp{Rela} relocations. With @samp{Rel} relocations, the addend +must be stored in the section contents, which makes relocatable links +more complex. + +For example, consider C code like @code{i = a[1000];} where @samp{a} is +a global array. The instructions which load the value of @samp{a[1000]} +will most likely use a relocation which refers to the symbol +representing @samp{a}, with an addend that gives the offset from the +start of @samp{a} to element @samp{1000}. When using @samp{Rel} +relocations, that addend must be stored in the instructions themselves. +If you are adding support for a RISC chip which uses two or more +instructions to load an address, then the addend may not fit in a single +instruction, and will have to be somehow split among the instructions. +This makes linking awkward, particularly when doing a relocatable link +in which the addend may have to be updated. It can be done---the MIPS +ELF support does it---but it should be avoided when possible. + +It is possible, though somewhat awkward, to support both @samp{Rel} and +@samp{Rela} relocations for a single target; @file{elf64-mips.c} does it +by overriding the relocation reading and writing routines. +@item +Define howto structures for all the relocation types. +@item +Define a @samp{bfd_reloc_type_lookup} routine. This must be named +@samp{bfd_elf@var{nn}_bfd_reloc_type_lookup}, and may be either a +function or a macro. It must translate a BFD relocation code into a +howto structure. This is normally a table lookup or a simple switch. +@item +If using @samp{Rel} relocations, define @samp{elf_info_to_howto_rel}. +If using @samp{Rela} relocations, define @samp{elf_info_to_howto}. +Either way, this is a macro defined as the name of a function which +takes an @samp{arelent} and a @samp{Rel} or @samp{Rela} structure, and +sets the @samp{howto} field of the @samp{arelent} based on the +@samp{Rel} or @samp{Rela} structure. This is normally uses +@samp{ELF@var{nn}_R_TYPE} to get the ELF relocation type and uses it as +an index into a table of howto structures. +@end itemize + +You must also add the magic number for this processor to the +@samp{prep_headers} function in @file{elf.c}. + +You must also create a header file in the @file{include/elf} directory +called @file{@var{cpu}.h}. This file should define any target specific +information which may be needed outside of the BFD code. In particular +it should use the @samp{START_RELOC_NUMBERS}, @samp{RELOC_NUMBER}, +@samp{FAKE_RELOC}, @samp{EMPTY_RELOC} and @samp{END_RELOC_NUMBERS} +macros to create a table mapping the number used to identify a +relocation to a name describing that relocation. + +While not a BFD component, you probably also want to make the binutils +program @samp{readelf} parse your ELF objects. For this, you need to add +code for @code{EM_@var{cpu}} as appropriate in @file{binutils/readelf.c}. + +@node BFD ELF processor linker +@subsubsection Processor specific linker support + +The linker will be much more efficient if you define a relocate section +function. This will permit BFD to use the ELF specific linker support. + +If you do not define a relocate section function, BFD must use the +generic linker support, which requires converting all symbols and +relocations into BFD @samp{asymbol} and @samp{arelent} structures. In +this case, relocations will be handled by calling +@samp{bfd_perform_relocation}, which will use the howto structures you +have defined. @xref{BFD relocation handling}. + +In order to support linking into a different object file format, such as +S-records, @samp{bfd_perform_relocation} must work correctly with your +howto structures, so you can't skip that step. However, if you define +the relocate section function, then in the normal case of linking into +an ELF file the linker will not need to convert symbols and relocations, +and will be much more efficient. + +To use a relocation section function, define the macro +@samp{elf_backend_relocate_section} as the name of a function which will +take the contents of a section, as well as relocation, symbol, and other +information, and modify the section contents according to the relocation +information. In simple cases, this is little more than a loop over the +relocations which computes the value of each relocation and calls +@samp{_bfd_final_link_relocate}. The function must check for a +relocatable link, and in that case normally needs to do nothing other +than adjust the addend for relocations against a section symbol. + +The complex cases generally have to do with dynamic linker support. GOT +and PLT relocations must be handled specially, and the linker normally +arranges to set up the GOT and PLT sections while handling relocations. +When generating a shared library, random relocations must normally be +copied into the shared library, or converted to RELATIVE relocations +when possible. + +@node BFD ELF processor other +@subsubsection Other processor specific support options + +There are many other macros which may be defined in +@file{elf@var{nn}-@var{cpu}.c}. These macros may be found in +@file{elfxx-target.h}. + +Macros may be used to override some of the generic ELF target vector +functions. + +Several processor specific hook functions which may be defined as +macros. These functions are found as function pointers in the +@samp{elf_backend_data} structure defined in @file{elf-bfd.h}. In +general, a hook function is set by defining a macro +@samp{elf_backend_@var{name}}. + +There are a few processor specific constants which may also be defined. +These are again found in the @samp{elf_backend_data} structure. + +I will not define the various functions and constants here; see the +comments in @file{elf-bfd.h}. + +Normally any odd characteristic of a particular ELF processor is handled +via a hook function. For example, the special @samp{SHN_MIPS_SCOMMON} +section number found in MIPS ELF is handled via the hooks +@samp{section_from_bfd_section}, @samp{symbol_processing}, +@samp{add_symbol_hook}, and @samp{output_symbol_hook}. + +Dynamic linking support, which involves processor specific relocations +requiring special handling, is also implemented via hook functions. + +@node BFD ELF core files +@subsection BFD ELF core files +@cindex elf core files + +On native ELF Unix systems, core files are generated without any +sections. Instead, they only have program segments. + +When BFD is used to read an ELF core file, the BFD sections will +actually represent program segments. Since ELF program segments do not +have names, BFD will invent names like @samp{segment@var{n}} where +@var{n} is a number. + +A single ELF program segment may include both an initialized part and an +uninitialized part. The size of the initialized part is given by the +@samp{p_filesz} field. The total size of the segment is given by the +@samp{p_memsz} field. If @samp{p_memsz} is larger than @samp{p_filesz}, +then the extra space is uninitialized, or, more precisely, initialized +to zero. + +BFD will represent such a program segment as two different sections. +The first, named @samp{segment@var{n}a}, will represent the initialized +part of the program segment. The second, named @samp{segment@var{n}b}, +will represent the uninitialized part. + +ELF core files store special information such as register values in +program segments with the type @samp{PT_NOTE}. BFD will attempt to +interpret the information in these segments, and will create additional +sections holding the information. Some of this interpretation requires +information found in the host header file @file{sys/procfs.h}, and so +will only work when BFD is built on a native system. + +BFD does not currently provide any way to create an ELF core file. In +general, BFD does not provide a way to create core files. The way to +implement this would be to write @samp{bfd_set_format} and +@samp{bfd_write_contents} routines for the @samp{bfd_core} type; see +@ref{BFD target vector format}. + +@node BFD ELF future +@subsection BFD ELF future + +The current dynamic linking support has too much code duplication. +While each processor has particular differences, much of the dynamic +linking support is quite similar for each processor. The GOT and PLT +are handled in fairly similar ways, the details of -Bsymbolic linking +are generally similar, etc. This code should be reworked to use more +generic functions, eliminating the duplication. + +Similarly, the relocation handling has too much duplication. Many of +the @samp{reloc_type_lookup} and @samp{info_to_howto} functions are +quite similar. The relocate section functions are also often quite +similar, both in the standard linker handling and the dynamic linker +handling. Many of the COFF processor specific backends share a single +relocate section function (@samp{_bfd_coff_generic_relocate_section}), +and it should be possible to do something like this for the ELF targets +as well. + +The appearance of the processor specific magic number in +@samp{prep_headers} in @file{elf.c} is somewhat bogus. It should be +possible to add support for a new processor without changing the generic +support. + +The processor function hooks and constants are ad hoc and need better +documentation. + +When a linker script uses @samp{SIZEOF_HEADERS}, the ELF backend must +guess at the number of program segments which will be required, in +@samp{get_program_header_size}. This is because the linker calls +@samp{bfd_sizeof_headers} before it knows all the section addresses and +sizes. The ELF backend may later discover, when creating program +segments, that more program segments are required. This is currently +reported as an error in @samp{assign_file_positions_for_segments}. + +In practice this makes it difficult to use @samp{SIZEOF_HEADERS} except +with a carefully defined linker script. Unfortunately, +@samp{SIZEOF_HEADERS} is required for fast program loading on a native +system, since it permits the initial code section to appear on the same +page as the program segments, saving a page read when the program starts +running. Fortunately, native systems permit careful definition of the +linker script. Still, ideally it would be possible to use relaxation to +compute the number of program segments. + +@node BFD glossary +@section BFD glossary +@cindex glossary for bfd +@cindex bfd glossary + +This is a short glossary of some BFD terms. + +@table @asis +@item a.out +The a.out object file format. The original Unix object file format. +Still used on SunOS, though not Solaris. Supports only three sections. + +@item archive +A collection of object files produced and manipulated by the @samp{ar} +program. + +@item backend +The implementation within BFD of a particular object file format. The +set of functions which appear in a particular target vector. + +@item BFD +The BFD library itself. Also, each object file, archive, or executable +opened by the BFD library has the type @samp{bfd *}, and is sometimes +referred to as a bfd. + +@item COFF +The Common Object File Format. Used on Unix SVR3. Used by some +embedded targets, although ELF is normally better. + +@item DLL +A shared library on Windows. + +@item dynamic linker +When a program linked against a shared library is run, the dynamic +linker will locate the appropriate shared library and arrange to somehow +include it in the running image. + +@item dynamic object +Another name for an ELF shared library. + +@item ECOFF +The Extended Common Object File Format. Used on Alpha Digital Unix +(formerly OSF/1), as well as Ultrix and Irix 4. A variant of COFF. + +@item ELF +The Executable and Linking Format. The object file format used on most +modern Unix systems, including GNU/Linux, Solaris, Irix, and SVR4. Also +used on many embedded systems. + +@item executable +A program, with instructions and symbols, and perhaps dynamic linking +information. Normally produced by a linker. + +@item LMA +Load Memory Address. This is the address at which a section will be +loaded. Compare with VMA, below. + +@item NLM +NetWare Loadable Module. Used to describe the format of an object which +be loaded into NetWare, which is some kind of PC based network server +program. + +@item object file +A binary file including machine instructions, symbols, and relocation +information. Normally produced by an assembler. + +@item object file format +The format of an object file. Typically object files and executables +for a particular system are in the same format, although executables +will not contain any relocation information. + +@item PE +The Portable Executable format. This is the object file format used for +Windows (specifically, Win32) object files. It is based closely on +COFF, but has a few significant differences. + +@item PEI +The Portable Executable Image format. This is the object file format +used for Windows (specifically, Win32) executables. It is very similar +to PE, but includes some additional header information. + +@item relocations +Information used by the linker to adjust section contents. Also called +relocs. + +@item section +Object files and executable are composed of sections. Sections have +optional data and optional relocation information. + +@item shared library +A library of functions which may be used by many executables without +actually being linked into each executable. There are several different +implementations of shared libraries, each having slightly different +features. + +@item symbol +Each object file and executable may have a list of symbols, often +referred to as the symbol table. A symbol is basically a name and an +address. There may also be some additional information like the type of +symbol, although the type of a symbol is normally something simple like +function or object, and should be confused with the more complex C +notion of type. Typically every global function and variable in a C +program will have an associated symbol. + +@item target vector +A set of functions which implement support for a particular object file +format. The @samp{bfd_target} structure. + +@item Win32 +The current Windows API, implemented by Windows 95 and later and Windows +NT 3.51 and later, but not by Windows 3.1. + +@item XCOFF +The eXtended Common Object File Format. Used on AIX. A variant of +COFF, with a completely different symbol table implementation. + +@item VMA +Virtual Memory Address. This is the address a section will have when +an executable is run. Compare with LMA, above. +@end table + +@node Index +@unnumberedsec Index +@printindex cp + +@contents +@bye diff --git a/contrib/binutils-2.17/bfd/doc/bfdio.texi b/contrib/binutils-2.17/bfd/doc/bfdio.texi new file mode 100644 index 0000000000..eb7e31df9d --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/bfdio.texi @@ -0,0 +1,72 @@ +@findex struct bfd_iovec +@subsubsection @code{struct bfd_iovec} +@strong{Description}@* +The @code{struct bfd_iovec} contains the internal file I/O class. +Each @code{BFD} has an instance of this class and all file I/O is +routed through it (it is assumed that the instance implements +all methods listed below). +@example +struct bfd_iovec +@{ + /* To avoid problems with macros, a "b" rather than "f" + prefix is prepended to each method name. */ + /* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching + bytes starting at PTR. Return the number of bytes actually + transfered (a read past end-of-file returns less than NBYTES), + or -1 (setting @code{bfd_error}) if an error occurs. */ + file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes); + file_ptr (*bwrite) (struct bfd *abfd, const void *ptr, + file_ptr nbytes); + /* Return the current IOSTREAM file offset, or -1 (setting @code{bfd_error} + if an error occurs. */ + file_ptr (*btell) (struct bfd *abfd); + /* For the following, on successful completion a value of 0 is returned. + Otherwise, a value of -1 is returned (and @code{bfd_error} is set). */ + int (*bseek) (struct bfd *abfd, file_ptr offset, int whence); + int (*bclose) (struct bfd *abfd); + int (*bflush) (struct bfd *abfd); + int (*bstat) (struct bfd *abfd, struct stat *sb); +@}; +@end example + +@findex bfd_get_mtime +@subsubsection @code{bfd_get_mtime} +@strong{Synopsis} +@example +long bfd_get_mtime (bfd *abfd); +@end example +@strong{Description}@* +Return the file modification time (as read from the file system, or +from the archive header for archive members). + +@findex bfd_get_size +@subsubsection @code{bfd_get_size} +@strong{Synopsis} +@example +long bfd_get_size (bfd *abfd); +@end example +@strong{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 @code{sizeof (long)} 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 question, "is the +size reasonable?". + diff --git a/contrib/binutils-2.17/bfd/doc/bfdsumm.texi b/contrib/binutils-2.17/bfd/doc/bfdsumm.texi new file mode 100644 index 0000000000..77a5f09e51 --- /dev/null +++ b/contrib/binutils-2.17/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.17/bfd/doc/bfdt.texi b/contrib/binutils-2.17/bfd/doc/bfdt.texi new file mode 100644 index 0000000000..a22fe3861d --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/bfdt.texi @@ -0,0 +1,721 @@ +@section @code{typedef bfd} +A BFD has type @code{bfd}; 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 @code{bfd}. It +contains the major data about the file and pointers +to the rest of the data. + + +@example + +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; + + /* The IOSTREAM, and corresponding IO vector that provide access + to the file backing the BFD. */ + void *iostream; + const struct bfd_iovec *iovec; + + /* 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 bfd_section *sections; + + /* The last section on the section list. */ + struct bfd_section *section_last; + + /* 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 bfd_symbol **outsymbols; + + /* Used for slurped dynamic symbol tables. */ + unsigned int dynsymcount; + + /* Pointer to structure which contains architecture information. */ + const struct bfd_arch_info *arch_info; + + /* Flag set if symbols from this BFD should not be exported. */ + bfd_boolean no_export; + + /* Stuff only useful for archives. */ + void *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; + void *any; + @} + tdata; + + /* Used by the application to hold private data. */ + void *usrdata; + + /* Where all the allocated stuff under this BFD goes. This is a + struct objalloc *, but we use void * to avoid requiring the inclusion + of objalloc.h. */ + void *memory; +@}; + +@end example +@section Error reporting +Most BFD functions return nonzero on success (check their +individual documentation for precise semantics). On an error, +they call @code{bfd_set_error} to set an error condition that callers +can check by calling @code{bfd_get_error}. +If that returns @code{bfd_error_system_call}, then check +@code{errno}. + +The easiest way to report a BFD error to the user is to +use @code{bfd_perror}. + +@subsection Type @code{bfd_error_type} +The values returned by @code{bfd_get_error} are defined by the +enumerated type @code{bfd_error_type}. + + +@example + +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; + +@end example +@findex bfd_get_error +@subsubsection @code{bfd_get_error} +@strong{Synopsis} +@example +bfd_error_type bfd_get_error (void); +@end example +@strong{Description}@* +Return the current BFD error condition. + +@findex bfd_set_error +@subsubsection @code{bfd_set_error} +@strong{Synopsis} +@example +void bfd_set_error (bfd_error_type error_tag); +@end example +@strong{Description}@* +Set the BFD error condition to be @var{error_tag}. + +@findex bfd_errmsg +@subsubsection @code{bfd_errmsg} +@strong{Synopsis} +@example +const char *bfd_errmsg (bfd_error_type error_tag); +@end example +@strong{Description}@* +Return a string describing the error @var{error_tag}, or +the system error if @var{error_tag} is @code{bfd_error_system_call}. + +@findex bfd_perror +@subsubsection @code{bfd_perror} +@strong{Synopsis} +@example +void bfd_perror (const char *message); +@end example +@strong{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. + +@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 overridden by the program. + +The BFD error handler acts like printf. + + +@example + +typedef void (*bfd_error_handler_type) (const char *, ...); + +@end example +@findex bfd_set_error_handler +@subsubsection @code{bfd_set_error_handler} +@strong{Synopsis} +@example +bfd_error_handler_type bfd_set_error_handler (bfd_error_handler_type); +@end example +@strong{Description}@* +Set the BFD error handler function. Returns the previous +function. + +@findex bfd_set_error_program_name +@subsubsection @code{bfd_set_error_program_name} +@strong{Synopsis} +@example +void bfd_set_error_program_name (const char *); +@end example +@strong{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. + +@findex bfd_get_error_handler +@subsubsection @code{bfd_get_error_handler} +@strong{Synopsis} +@example +bfd_error_handler_type bfd_get_error_handler (void); +@end example +@strong{Description}@* +Return the BFD error handler function. + +@section Miscellaneous + + +@subsection Miscellaneous functions + + +@findex bfd_get_reloc_upper_bound +@subsubsection @code{bfd_get_reloc_upper_bound} +@strong{Synopsis} +@example +long bfd_get_reloc_upper_bound (bfd *abfd, asection *sect); +@end example +@strong{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. + +@findex bfd_canonicalize_reloc +@subsubsection @code{bfd_canonicalize_reloc} +@strong{Synopsis} +@example +long bfd_canonicalize_reloc + (bfd *abfd, asection *sec, arelent **loc, asymbol **syms); +@end example +@strong{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 +@code{bfd_get_reloc_upper_bound}. Returns the number of relocs, or +-1 on error. + +The @var{syms} table is also needed for horrible internal magic +reasons. + +@findex bfd_set_reloc +@subsubsection @code{bfd_set_reloc} +@strong{Synopsis} +@example +void bfd_set_reloc + (bfd *abfd, asection *sec, arelent **rel, unsigned int count); +@end example +@strong{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. + +@findex bfd_set_file_flags +@subsubsection @code{bfd_set_file_flags} +@strong{Synopsis} +@example +bfd_boolean bfd_set_file_flags (bfd *abfd, flagword flags); +@end example +@strong{Description}@* +Set the flag word in the BFD @var{abfd} to the value @var{flags}. + +Possible errors are: +@itemize @bullet + +@item +@code{bfd_error_wrong_format} - The target bfd was not of object format. +@item +@code{bfd_error_invalid_operation} - The target bfd was open for reading. +@item +@code{bfd_error_invalid_operation} - +The flag word contained a bit which was not applicable to the +type of file. E.g., an attempt was made to set the @code{D_PAGED} bit +on a BFD format which does not support demand paging. +@end itemize + +@findex bfd_get_arch_size +@subsubsection @code{bfd_get_arch_size} +@strong{Synopsis} +@example +int bfd_get_arch_size (bfd *abfd); +@end example +@strong{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. + +@strong{Returns}@* +Returns the arch size in bits if known, @code{-1} otherwise. + +@findex bfd_get_sign_extend_vma +@subsubsection @code{bfd_get_sign_extend_vma} +@strong{Synopsis} +@example +int bfd_get_sign_extend_vma (bfd *abfd); +@end example +@strong{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. + +@strong{Returns}@* +Returns @code{1} if the target architecture is known to sign +extend addresses, @code{0} if the target architecture is known to +not sign extend addresses, and @code{-1} otherwise. + +@findex bfd_set_start_address +@subsubsection @code{bfd_set_start_address} +@strong{Synopsis} +@example +bfd_boolean bfd_set_start_address (bfd *abfd, bfd_vma vma); +@end example +@strong{Description}@* +Make @var{vma} the entry point of output BFD @var{abfd}. + +@strong{Returns}@* +Returns @code{TRUE} on success, @code{FALSE} otherwise. + +@findex bfd_get_gp_size +@subsubsection @code{bfd_get_gp_size} +@strong{Synopsis} +@example +unsigned int bfd_get_gp_size (bfd *abfd); +@end example +@strong{Description}@* +Return the maximum size of objects to be optimized using the GP +register under MIPS ECOFF. This is typically set by the @code{-G} +argument to the compiler, assembler or linker. + +@findex bfd_set_gp_size +@subsubsection @code{bfd_set_gp_size} +@strong{Synopsis} +@example +void bfd_set_gp_size (bfd *abfd, unsigned int i); +@end example +@strong{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 @code{-G} argument to the compiler, assembler or linker. + +@findex bfd_scan_vma +@subsubsection @code{bfd_scan_vma} +@strong{Synopsis} +@example +bfd_vma bfd_scan_vma (const char *string, const char **end, int base); +@end example +@strong{Description}@* +Convert, like @code{strtoul}, a numerical expression +@var{string} into a @code{bfd_vma} integer, and return that integer. +(Though without as many bells and whistles as @code{strtoul}.) +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 @code{bfd_vma} value is +returned. + +@findex bfd_copy_private_header_data +@subsubsection @code{bfd_copy_private_header_data} +@strong{Synopsis} +@example +bfd_boolean bfd_copy_private_header_data (bfd *ibfd, bfd *obfd); +@end example +@strong{Description}@* +Copy private BFD header information from the BFD @var{ibfd} to the +the BFD @var{obfd}. This copies information that may require +sections to exist, but does not require symbol tables. Return +@code{true} on success, @code{false} on error. +Possible error returns are: + +@itemize @bullet + +@item +@code{bfd_error_no_memory} - +Not enough memory exists to create private data for @var{obfd}. +@end itemize +@example +#define bfd_copy_private_header_data(ibfd, obfd) \ + BFD_SEND (obfd, _bfd_copy_private_header_data, \ + (ibfd, obfd)) +@end example + +@findex bfd_copy_private_bfd_data +@subsubsection @code{bfd_copy_private_bfd_data} +@strong{Synopsis} +@example +bfd_boolean bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd); +@end example +@strong{Description}@* +Copy private BFD information from the BFD @var{ibfd} to the +the BFD @var{obfd}. Return @code{TRUE} on success, @code{FALSE} on error. +Possible error returns are: + +@itemize @bullet + +@item +@code{bfd_error_no_memory} - +Not enough memory exists to create private data for @var{obfd}. +@end itemize +@example +#define bfd_copy_private_bfd_data(ibfd, obfd) \ + BFD_SEND (obfd, _bfd_copy_private_bfd_data, \ + (ibfd, obfd)) +@end example + +@findex bfd_merge_private_bfd_data +@subsubsection @code{bfd_merge_private_bfd_data} +@strong{Synopsis} +@example +bfd_boolean bfd_merge_private_bfd_data (bfd *ibfd, bfd *obfd); +@end example +@strong{Description}@* +Merge private BFD information from the BFD @var{ibfd} to the +the output file BFD @var{obfd} when linking. Return @code{TRUE} +on success, @code{FALSE} on error. Possible error returns are: + +@itemize @bullet + +@item +@code{bfd_error_no_memory} - +Not enough memory exists to create private data for @var{obfd}. +@end itemize +@example +#define bfd_merge_private_bfd_data(ibfd, obfd) \ + BFD_SEND (obfd, _bfd_merge_private_bfd_data, \ + (ibfd, obfd)) +@end example + +@findex bfd_set_private_flags +@subsubsection @code{bfd_set_private_flags} +@strong{Synopsis} +@example +bfd_boolean bfd_set_private_flags (bfd *abfd, flagword flags); +@end example +@strong{Description}@* +Set private BFD flag information in the BFD @var{abfd}. +Return @code{TRUE} on success, @code{FALSE} on error. Possible error +returns are: + +@itemize @bullet + +@item +@code{bfd_error_no_memory} - +Not enough memory exists to create private data for @var{obfd}. +@end itemize +@example +#define bfd_set_private_flags(abfd, flags) \ + BFD_SEND (abfd, _bfd_set_private_flags, (abfd, flags)) +@end example + +@findex Other functions +@subsubsection @code{Other functions} +@strong{Description}@* +The following functions exist but have not yet been documented. +@example +#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_find_line(abfd, syms, sym, file, line) \ + BFD_SEND (abfd, _bfd_find_line, \ + (abfd, syms, sym, file, line)) + +#define bfd_find_inliner_info(abfd, file, func, line) \ + BFD_SEND (abfd, _bfd_find_inliner_info, \ + (abfd, 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_is_group_section(abfd, sec) \ + BFD_SEND (abfd, _bfd_is_group_section, (abfd, sec)) + +#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(abfd, 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_synthetic_symtab(abfd, count, syms, dyncount, dynsyms, ret) \ + BFD_SEND (abfd, _bfd_get_synthetic_symtab, (abfd, count, syms, \ + dyncount, dynsyms, ret)) + +#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 + (bfd *, struct bfd_link_info *, struct bfd_link_order *, bfd_byte *, + bfd_boolean, asymbol **); + +@end example + +@findex bfd_alt_mach_code +@subsubsection @code{bfd_alt_mach_code} +@strong{Synopsis} +@example +bfd_boolean bfd_alt_mach_code (bfd *abfd, int alternative); +@end example +@strong{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. + + +@example +struct bfd_preserve +@{ + void *marker; + void *tdata; + flagword flags; + const struct bfd_arch_info *arch_info; + struct bfd_section *sections; + struct bfd_section *section_last; + unsigned int section_count; + struct bfd_hash_table section_htab; +@}; + +@end example +@findex bfd_preserve_save +@subsubsection @code{bfd_preserve_save} +@strong{Synopsis} +@example +bfd_boolean bfd_preserve_save (bfd *, struct bfd_preserve *); +@end example +@strong{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. + +@findex bfd_preserve_restore +@subsubsection @code{bfd_preserve_restore} +@strong{Synopsis} +@example +void bfd_preserve_restore (bfd *, struct bfd_preserve *); +@end example +@strong{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. + +@findex bfd_preserve_finish +@subsubsection @code{bfd_preserve_finish} +@strong{Synopsis} +@example +void bfd_preserve_finish (bfd *, struct bfd_preserve *); +@end example +@strong{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. + diff --git a/contrib/binutils-2.17/bfd/doc/bfdwin.texi b/contrib/binutils-2.17/bfd/doc/bfdwin.texi new file mode 100644 index 0000000000..b1fd7d5bed --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/bfdwin.texi @@ -0,0 +1,2 @@ +@findex +@subsubsection @code{} diff --git a/contrib/binutils-2.17/bfd/doc/cache.texi b/contrib/binutils-2.17/bfd/doc/cache.texi new file mode 100644 index 0000000000..5820a2a6a1 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/cache.texi @@ -0,0 +1,65 @@ +@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 +@code{cache.c} maintains a least recently used list of +@code{BFD_CACHE_MAX_OPEN} files, and exports the name +@code{bfd_cache_lookup}, 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. + +@subsection Caching functions + + +@findex bfd_cache_init +@subsubsection @code{bfd_cache_init} +@strong{Synopsis} +@example +bfd_boolean bfd_cache_init (bfd *abfd); +@end example +@strong{Description}@* +Add a newly opened BFD to the cache. + +@findex bfd_cache_close +@subsubsection @code{bfd_cache_close} +@strong{Synopsis} +@example +bfd_boolean bfd_cache_close (bfd *abfd); +@end example +@strong{Description}@* +Remove the BFD @var{abfd} from the cache. If the attached file is open, +then close it too. + +@strong{Returns}@* +@code{FALSE} is returned if closing the file fails, @code{TRUE} is +returned if all is well. + +@findex bfd_cache_close_all +@subsubsection @code{bfd_cache_close_all} +@strong{Synopsis} +@example +bfd_boolean bfd_cache_close_all (void); +@end example +@strong{Description}@* +Remove all BFDs from the cache. If the attached file is open, +then close it too. + +@strong{Returns}@* +@code{FALSE} is returned if closing one of the file fails, @code{TRUE} is +returned if all is well. + +@findex bfd_open_file +@subsubsection @code{bfd_open_file} +@strong{Synopsis} +@example +FILE* bfd_open_file (bfd *abfd); +@end example +@strong{Description}@* +Call the OS to open a file for @var{abfd}. Return the @code{FILE *} +(possibly @code{NULL}) that results from this operation. Set up the +BFD so that future accesses know the file is open. If the @code{FILE *} +returned is @code{NULL}, then it won't have been put in the +cache, so it won't have to be removed from it. + diff --git a/contrib/binutils-2.17/bfd/doc/coffcode.texi b/contrib/binutils-2.17/bfd/doc/coffcode.texi new file mode 100644 index 0000000000..6689009c08 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/coffcode.texi @@ -0,0 +1,608 @@ +@section coff backends +BFD supports a number of different flavours of coff format. +The major differences between formats are the sizes and +alignments of fields in structures on disk, and the occasional +extra field. + +Coff in all its varieties is implemented with a few common +files and a number of implementation specific files. For +example, The 88k bcs coff format is implemented in the file +@file{coff-m88k.c}. This file @code{#include}s +@file{coff/m88k.h} which defines the external structure of the +coff format for the 88k, and @file{coff/internal.h} which +defines the internal structure. @file{coff-m88k.c} also +defines the relocations used by the 88k format +@xref{Relocations}. + +The Intel i960 processor version of coff is implemented in +@file{coff-i960.c}. This file has the same structure as +@file{coff-m88k.c}, except that it includes @file{coff/i960.h} +rather than @file{coff-m88k.h}. + +@subsection Porting to a new version of coff +The recommended method is to select from the existing +implementations the version of coff which is most like the one +you want to use. For example, we'll say that i386 coff is +the one you select, and that your coff flavour is called foo. +Copy @file{i386coff.c} to @file{foocoff.c}, copy +@file{../include/coff/i386.h} to @file{../include/coff/foo.h}, +and add the lines to @file{targets.c} and @file{Makefile.in} +so that your new back end is used. Alter the shapes of the +structures in @file{../include/coff/foo.h} so that they match +what you need. You will probably also have to add +@code{#ifdef}s to the code in @file{coff/internal.h} and +@file{coffcode.h} if your version of coff is too wild. + +You can verify that your new BFD backend works quite simply by +building @file{objdump} from the @file{binutils} directory, +and making sure that its version of what's going on and your +host system's idea (assuming it has the pretty standard coff +dump utility, usually called @code{att-dump} or just +@code{dump}) are the same. Then clean up your code, and send +what you've done to Cygnus. Then your stuff will be in the +next release, and you won't have to keep integrating it. + +@subsection How the coff backend works + + +@subsubsection File layout +The Coff backend is split into generic routines that are +applicable to any Coff target and routines that are specific +to a particular target. The target-specific routines are +further split into ones which are basically the same for all +Coff targets except that they use the external symbol format +or use different values for certain constants. + +The generic routines are in @file{coffgen.c}. These routines +work for any Coff target. They use some hooks into the target +specific code; the hooks are in a @code{bfd_coff_backend_data} +structure, one of which exists for each target. + +The essentially similar target-specific routines are in +@file{coffcode.h}. This header file includes executable C code. +The various Coff targets first include the appropriate Coff +header file, make any special defines that are needed, and +then include @file{coffcode.h}. + +Some of the Coff targets then also have additional routines in +the target source file itself. + +For example, @file{coff-i960.c} includes +@file{coff/internal.h} and @file{coff/i960.h}. It then +defines a few constants, such as @code{I960}, and includes +@file{coffcode.h}. Since the i960 has complex relocation +types, @file{coff-i960.c} also includes some code to +manipulate the i960 relocs. This code is not in +@file{coffcode.h} because it would not be used by any other +target. + +@subsubsection Bit twiddling +Each flavour of coff supported in BFD has its own header file +describing the external layout of the structures. There is also +an internal description of the coff layout, in +@file{coff/internal.h}. A major function of the +coff backend is swapping the bytes and twiddling the bits to +translate the external form of the structures into the normal +internal form. This is all performed in the +@code{bfd_swap}_@i{thing}_@i{direction} routines. Some +elements are different sizes between different versions of +coff; it is the duty of the coff version specific include file +to override the definitions of various packing routines in +@file{coffcode.h}. E.g., the size of line number entry in coff is +sometimes 16 bits, and sometimes 32 bits. @code{#define}ing +@code{PUT_LNSZ_LNNO} and @code{GET_LNSZ_LNNO} will select the +correct one. No doubt, some day someone will find a version of +coff which has a varying field size not catered to at the +moment. To port BFD, that person will have to add more @code{#defines}. +Three of the bit twiddling routines are exported to +@code{gdb}; @code{coff_swap_aux_in}, @code{coff_swap_sym_in} +and @code{coff_swap_lineno_in}. @code{GDB} reads the symbol +table on its own, but uses BFD to fix things up. More of the +bit twiddlers are exported for @code{gas}; +@code{coff_swap_aux_out}, @code{coff_swap_sym_out}, +@code{coff_swap_lineno_out}, @code{coff_swap_reloc_out}, +@code{coff_swap_filehdr_out}, @code{coff_swap_aouthdr_out}, +@code{coff_swap_scnhdr_out}. @code{Gas} currently keeps track +of all the symbol table and reloc drudgery itself, thereby +saving the internal BFD overhead, but uses BFD to swap things +on the way out, making cross ports much safer. Doing so also +allows BFD (and thus the linker) to use the same header files +as @code{gas}, which makes one avenue to disaster disappear. + +@subsubsection Symbol reading +The simple canonical form for symbols used by BFD is not rich +enough to keep all the information available in a coff symbol +table. The back end gets around this problem by keeping the original +symbol table around, "behind the scenes". + +When a symbol table is requested (through a call to +@code{bfd_canonicalize_symtab}), a request gets through to +@code{coff_get_normalized_symtab}. This reads the symbol table from +the coff file and swaps all the structures inside into the +internal form. It also fixes up all the pointers in the table +(represented in the file by offsets from the first symbol in +the table) into physical pointers to elements in the new +internal table. This involves some work since the meanings of +fields change depending upon context: a field that is a +pointer to another structure in the symbol table at one moment +may be the size in bytes of a structure at the next. Another +pass is made over the table. All symbols which mark file names +(@code{C_FILE} symbols) are modified so that the internal +string points to the value in the auxent (the real filename) +rather than the normal text associated with the symbol +(@code{".file"}). + +At this time the symbol names are moved around. Coff stores +all symbols less than nine characters long physically +within the symbol table; longer strings are kept at the end of +the file in the string table. This pass moves all strings +into memory and replaces them with pointers to the strings. + +The symbol table is massaged once again, this time to create +the canonical table used by the BFD application. Each symbol +is inspected in turn, and a decision made (using the +@code{sclass} field) about the various flags to set in the +@code{asymbol}. @xref{Symbols}. The generated canonical table +shares strings with the hidden internal symbol table. + +Any linenumbers are read from the coff file too, and attached +to the symbols which own the functions the linenumbers belong to. + +@subsubsection Symbol writing +Writing a symbol to a coff file which didn't come from a coff +file will lose any debugging information. The @code{asymbol} +structure remembers the BFD from which the symbol was taken, and on +output the back end makes sure that the same destination target as +source target is present. + +When the symbols have come from a coff file then all the +debugging information is preserved. + +Symbol tables are provided for writing to the back end in a +vector of pointers to pointers. This allows applications like +the linker to accumulate and output large symbol tables +without having to do too much byte copying. + +This function runs through the provided symbol table and +patches each symbol marked as a file place holder +(@code{C_FILE}) to point to the next file place holder in the +list. It also marks each @code{offset} field in the list with +the offset from the first symbol of the current symbol. + +Another function of this procedure is to turn the canonical +value form of BFD into the form used by coff. Internally, BFD +expects symbol values to be offsets from a section base; so a +symbol physically at 0x120, but in a section starting at +0x100, would have the value 0x20. Coff expects symbols to +contain their final value, so symbols have their values +changed at this point to reflect their sum with their owning +section. This transformation uses the +@code{output_section} field of the @code{asymbol}'s +@code{asection} @xref{Sections}. + +@itemize @bullet + +@item +@code{coff_mangle_symbols} +@end itemize +This routine runs though the provided symbol table and uses +the offsets generated by the previous pass and the pointers +generated when the symbol table was read in to create the +structured hierarchy required by coff. It changes each pointer +to a symbol into the index into the symbol table of the asymbol. + +@itemize @bullet + +@item +@code{coff_write_symbols} +@end itemize +This routine runs through the symbol table and patches up the +symbols from their internal form into the coff way, calls the +bit twiddlers, and writes out the table to the file. + +@findex coff_symbol_type +@subsubsection @code{coff_symbol_type} +@strong{Description}@* +The hidden information for an @code{asymbol} is described in a +@code{combined_entry_type}: + + +@example + +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; +@end example +@findex bfd_coff_backend_data +@subsubsection @code{bfd_coff_backend_data} + +@example +/* 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 +@}; + +@end example +Special entry points for gdb to swap in coff symbol table parts: +@example +typedef struct +@{ + void (*_bfd_coff_swap_aux_in) + (bfd *, void *, int, int, int, int, void *); + + void (*_bfd_coff_swap_sym_in) + (bfd *, void *, void *); + + void (*_bfd_coff_swap_lineno_in) + (bfd *, void *, void *); + + unsigned int (*_bfd_coff_swap_aux_out) + (bfd *, void *, int, int, int, int, void *); + + unsigned int (*_bfd_coff_swap_sym_out) + (bfd *, void *, void *); + + unsigned int (*_bfd_coff_swap_lineno_out) + (bfd *, void *, void *); + + unsigned int (*_bfd_coff_swap_reloc_out) + (bfd *, void *, void *); + + unsigned int (*_bfd_coff_swap_filehdr_out) + (bfd *, void *, void *); + + unsigned int (*_bfd_coff_swap_aouthdr_out) + (bfd *, void *, void *); + + unsigned int (*_bfd_coff_swap_scnhdr_out) + (bfd *, void *, void *); + + 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) + (bfd *, void *, void *); + + void (*_bfd_coff_swap_aouthdr_in) + (bfd *, void *, void *); + + void (*_bfd_coff_swap_scnhdr_in) + (bfd *, void *, void *); + + void (*_bfd_coff_swap_reloc_in) + (bfd *abfd, void *, void *); + + bfd_boolean (*_bfd_coff_bad_format_hook) + (bfd *, void *); + + bfd_boolean (*_bfd_coff_set_arch_mach_hook) + (bfd *, void *); + + void * (*_bfd_coff_mkobject_hook) + (bfd *, void *, void *); + + bfd_boolean (*_bfd_styp_to_sec_flags_hook) + (bfd *, void *, const char *, asection *, flagword *); + + void (*_bfd_set_alignment_hook) + (bfd *, asection *, void *); + + bfd_boolean (*_bfd_coff_slurp_symbol_table) + (bfd *); + + bfd_boolean (*_bfd_coff_symname_in_debug) + (bfd *, struct internal_syment *); + + bfd_boolean (*_bfd_coff_pointerize_aux_hook) + (bfd *, combined_entry_type *, combined_entry_type *, + unsigned int, combined_entry_type *); + + bfd_boolean (*_bfd_coff_print_aux) + (bfd *, FILE *, combined_entry_type *, combined_entry_type *, + combined_entry_type *, unsigned int); + + void (*_bfd_coff_reloc16_extra_cases) + (bfd *, struct bfd_link_info *, struct bfd_link_order *, arelent *, + bfd_byte *, unsigned int *, unsigned int *); + + int (*_bfd_coff_reloc16_estimate) + (bfd *, asection *, arelent *, unsigned int, + struct bfd_link_info *); + + enum coff_symbol_classification (*_bfd_coff_classify_symbol) + (bfd *, struct internal_syment *); + + bfd_boolean (*_bfd_coff_compute_section_file_positions) + (bfd *); + + bfd_boolean (*_bfd_coff_start_final_link) + (bfd *, struct bfd_link_info *); + + bfd_boolean (*_bfd_coff_relocate_section) + (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + struct internal_reloc *, struct internal_syment *, asection **); + + reloc_howto_type *(*_bfd_coff_rtype_to_howto) + (bfd *, asection *, struct internal_reloc *, + struct coff_link_hash_entry *, struct internal_syment *, + bfd_vma *); + + bfd_boolean (*_bfd_coff_adjust_symndx) + (bfd *, struct bfd_link_info *, bfd *, asection *, + struct internal_reloc *, bfd_boolean *); + + bfd_boolean (*_bfd_coff_link_add_one_symbol) + (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) + (bfd *, struct coff_final_link_info *); + + bfd_boolean (*_bfd_coff_final_link_postscript) + (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)) + +@end example +@subsubsection Writing relocations +To write relocations, the back end steps though the +canonical relocation table and create an +@code{internal_reloc}. The symbol index to use is removed from +the @code{offset} field in the symbol table supplied. The +address comes directly from the sum of the section base +address and the relocation offset; the type is dug directly +from the howto field. Then the @code{internal_reloc} is +swapped into the shape of an @code{external_reloc} and written +out to disk. + +@subsubsection Reading linenumbers +Creating the linenumber table is done by reading in the entire +coff linenumber table, and creating another table for internal use. + +A coff linenumber table is structured so that each function +is marked as having a line number of 0. Each line within the +function is an offset from the first line in the function. The +base of the line number information for the table is stored in +the symbol associated with the function. + +Note: The PE format uses line number 0 for a flag indicating a +new source file. + +The information is copied from the external to the internal +table, and each symbol which marks a function is marked by +pointing its... + +How does this work ? + +@subsubsection Reading relocations +Coff relocations are easily transformed into the internal BFD form +(@code{arelent}). + +Reading a coff relocation table is done in the following stages: + +@itemize @bullet + +@item +Read the entire coff relocation table into memory. + +@item +Process each relocation in turn; first swap it from the +external to the internal form. + +@item +Turn the symbol referenced in the relocation's symbol index +into a pointer into the canonical symbol table. +This table is the same as the one returned by a call to +@code{bfd_canonicalize_symtab}. The back end will call that +routine and save the result if a canonicalization hasn't been done. + +@item +The reloc index is turned into a pointer to a howto +structure, in a back end specific way. For instance, the 386 +and 960 use the @code{r_type} to directly produce an index +into a howto table vector; the 88k subtracts a number from the +@code{r_type} field and creates an addend field. +@end itemize + diff --git a/contrib/binutils-2.17/bfd/doc/core.texi b/contrib/binutils-2.17/bfd/doc/core.texi new file mode 100644 index 0000000000..1f09445ef7 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/core.texi @@ -0,0 +1,60 @@ +@section Core files + + +@subsection Core file functions + + +@strong{Description}@* +These are functions pertaining to core files. + +@findex bfd_core_file_failing_command +@subsubsection @code{bfd_core_file_failing_command} +@strong{Synopsis} +@example +const char *bfd_core_file_failing_command (bfd *abfd); +@end example +@strong{Description}@* +Return a read-only string explaining which program was running +when it failed and produced the core file @var{abfd}. + +@findex bfd_core_file_failing_signal +@subsubsection @code{bfd_core_file_failing_signal} +@strong{Synopsis} +@example +int bfd_core_file_failing_signal (bfd *abfd); +@end example +@strong{Description}@* +Returns the signal number which caused the core dump which +generated the file the BFD @var{abfd} is attached to. + +@findex core_file_matches_executable_p +@subsubsection @code{core_file_matches_executable_p} +@strong{Synopsis} +@example +bfd_boolean core_file_matches_executable_p + (bfd *core_bfd, bfd *exec_bfd); +@end example +@strong{Description}@* +Return @code{TRUE} if the core file attached to @var{core_bfd} +was generated by a run of the executable file attached to +@var{exec_bfd}, @code{FALSE} otherwise. + +@findex generic_core_file_matches_executable_p +@subsubsection @code{generic_core_file_matches_executable_p} +@strong{Synopsis} +@example +bfd_boolean generic_core_file_matches_executable_p + (bfd *core_bfd, bfd *exec_bfd); +@end example +@strong{Description}@* +Return TRUE if the core file attached to @var{core_bfd} +was generated by a run of the executable file attached +to @var{exec_bfd}. The match is based on executable +basenames only. + +Note: When not able to determine the core file failing +command or the executable name, we still return TRUE even +though we're not sure that core file and executable match. +This is to avoid generating a false warning in situations +where we really don't know whether they match or not. + diff --git a/contrib/binutils-2.17/bfd/doc/elf.texi b/contrib/binutils-2.17/bfd/doc/elf.texi new file mode 100644 index 0000000000..4f9434cf69 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/elf.texi @@ -0,0 +1,22 @@ +@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. + +@findex bfd_elf_find_section +@subsubsection @code{bfd_elf_find_section} +@strong{Synopsis} +@example +struct elf_internal_shdr *bfd_elf_find_section (bfd *abfd, char *name); +@end example +@strong{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. + diff --git a/contrib/binutils-2.17/bfd/doc/elfcode.texi b/contrib/binutils-2.17/bfd/doc/elfcode.texi new file mode 100644 index 0000000000..e69de29bb2 diff --git a/contrib/binutils-2.17/bfd/doc/format.texi b/contrib/binutils-2.17/bfd/doc/format.texi new file mode 100644 index 0000000000..9674acff44 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/format.texi @@ -0,0 +1,112 @@ +@section File formats +A format is a BFD concept of high level file contents type. The +formats supported by BFD are: + +@itemize @bullet + +@item +@code{bfd_object} +@end itemize +The BFD may contain data, symbols, relocations and debug info. + +@itemize @bullet + +@item +@code{bfd_archive} +@end itemize +The BFD contains other BFDs and an optional index. + +@itemize @bullet + +@item +@code{bfd_core} +@end itemize +The BFD contains the result of an executable core dump. + +@subsection File format functions + + +@findex bfd_check_format +@subsubsection @code{bfd_check_format} +@strong{Synopsis} +@example +bfd_boolean bfd_check_format (bfd *abfd, bfd_format format); +@end example +@strong{Description}@* +Verify if the file attached to the BFD @var{abfd} is compatible +with the format @var{format} (i.e., one of @code{bfd_object}, +@code{bfd_archive} or @code{bfd_core}). + +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 +@code{default}, 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 @code{TRUE} on success, otherwise @code{FALSE} +with one of the following error codes: + +@itemize @bullet + +@item +@code{bfd_error_invalid_operation} - +if @code{format} is not one of @code{bfd_object}, @code{bfd_archive} or +@code{bfd_core}. + +@item +@code{bfd_error_system_call} - +if an error occured during a read - even some file mismatches +can cause bfd_error_system_calls. + +@item +@code{file_not_recognised} - +none of the backends recognised the file format. + +@item +@code{bfd_error_file_ambiguously_recognized} - +more than one backend recognised the file format. +@end itemize + +@findex bfd_check_format_matches +@subsubsection @code{bfd_check_format_matches} +@strong{Synopsis} +@example +bfd_boolean bfd_check_format_matches + (bfd *abfd, bfd_format format, char ***matching); +@end example +@strong{Description}@* +Like @code{bfd_check_format}, except when it returns FALSE with +@code{bfd_errno} set to @code{bfd_error_file_ambiguously_recognized}. 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 @code{malloc}. +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. + +@findex bfd_set_format +@subsubsection @code{bfd_set_format} +@strong{Synopsis} +@example +bfd_boolean bfd_set_format (bfd *abfd, bfd_format format); +@end example +@strong{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. + +@findex bfd_format_string +@subsubsection @code{bfd_format_string} +@strong{Synopsis} +@example +const char *bfd_format_string (bfd_format format); +@end example +@strong{Description}@* +Return a pointer to a const string +@code{invalid}, @code{object}, @code{archive}, @code{core}, or @code{unknown}, +depending upon the value of @var{format}. + diff --git a/contrib/binutils-2.17/bfd/doc/hash.texi b/contrib/binutils-2.17/bfd/doc/hash.texi new file mode 100644 index 0000000000..88d9585cc4 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/hash.texi @@ -0,0 +1,247 @@ +@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 @code{hash.c}. + +@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 + +@node 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 @code{struct +bfd_hash_table} (defined in @code{bfd.h}) and call +@code{bfd_hash_table_init} (if you know approximately how many +entries you will need, the function @code{bfd_hash_table_init_n}, +which takes a @var{size} argument, may be used). +@code{bfd_hash_table_init} returns @code{FALSE} if some sort of +error occurs. + +@findex bfd_hash_newfunc +The function @code{bfd_hash_table_init} take as an argument a +function to use to create new entries. For a basic hash +table, use the function @code{bfd_hash_newfunc}. @xref{Deriving +a New Hash Table Type}, for why you would want to use a +different value for this argument. + +@findex bfd_hash_allocate +@code{bfd_hash_table_init} will create an objalloc which will be +used to allocate new entries. You may allocate memory on this +objalloc using @code{bfd_hash_allocate}. + +@findex bfd_hash_table_free +Use @code{bfd_hash_table_free} to free up all the memory that has +been allocated for a hash table. This will not free up the +@code{struct bfd_hash_table} itself, which you must provide. + +@findex bfd_hash_set_default_size +Use @code{bfd_hash_set_default_size} to set the default size of +hash table to use. + +@node 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 @code{bfd_hash_lookup} is used both to look up a +string in the hash table and to create a new entry. + +If the @var{create} argument is @code{FALSE}, @code{bfd_hash_lookup} +will look up a string. If the string is found, it will +returns a pointer to a @code{struct bfd_hash_entry}. If the +string is not found in the table @code{bfd_hash_lookup} will +return @code{NULL}. You should not modify any of the fields in +the returns @code{struct bfd_hash_entry}. + +If the @var{create} argument is @code{TRUE}, the string will be +entered into the hash table if it is not already there. +Either way a pointer to a @code{struct bfd_hash_entry} will be +returned, either to the existing structure or to a newly +created one. In this case, a @code{NULL} return means that an +error occurred. + +If the @var{create} argument is @code{TRUE}, 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 @code{FALSE}, you must be careful not to +deallocate or modify the string as long as the hash table +exists. + +@node 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 @code{bfd_hash_traverse} may be used to traverse a +hash table, calling a function on each element. The traversal +is done in a random order. + +@code{bfd_hash_traverse} takes as arguments a function and a +generic @code{void *} pointer. The function is called with a +hash table entry (a @code{struct bfd_hash_entry *}) and the +generic pointer passed to @code{bfd_hash_traverse}. The function +must return a @code{boolean} value, which indicates whether to +continue traversing the hash table. If the function returns +@code{FALSE}, @code{bfd_hash_traverse} will stop the traversal and +return immediately. + +@node 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 @code{bfdlink.h}. The +functions are in @code{linker.c}. + +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 + +@node 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 @code{struct bfd_hash_entry}, which is defined in +@code{bfd.h}. 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 @code{struct bfd_hash_table}. + +For example, the linker hash table defines @code{struct +bfd_link_hash_entry} (in @code{bfdlink.h}). The first field, +@code{root}, is of type @code{struct bfd_hash_entry}. Similarly, +the first field in @code{struct bfd_link_hash_table}, @code{table}, +is of type @code{struct bfd_hash_table}. + +@node 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 @code{bfd_hash_table_init}. + +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 @code{NULL}, 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} (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 == NULL) + @{ + ret = bfd_hash_allocate (table, sizeof (* ret)); + if (ret == 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; +@} +@end example +@strong{Description}@* +The creation routine for the linker hash table, which is in +@code{linker.c}, looks just like this example. +@var{function_name} is @code{_bfd_link_hash_newfunc}. +@var{entry_type} is @code{struct bfd_link_hash_entry}. +@var{base_newfunc} is @code{bfd_hash_newfunc}, the creation +routine for a basic hash table. + +@code{_bfd_link_hash_newfunc} also initializes the local fields +in a linker hash table entry: @code{type}, @code{written} and +@code{next}. + +@node 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 @code{_bfd_link_hash_table_init} in @code{linker.c}. + +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 @code{bfd_link_hash_lookup} in +@code{linker.c} (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 +@code{bfd_link_hash_traverse} in @code{linker.c}. + +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 @code{aout_link_hash_lookup} and +@code{aout_link_hash_traverse} in aoutx.h. + diff --git a/contrib/binutils-2.17/bfd/doc/init.texi b/contrib/binutils-2.17/bfd/doc/init.texi new file mode 100644 index 0000000000..ab735f8e98 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/init.texi @@ -0,0 +1,16 @@ +@section Initialization + + +@subsection Initialization functions +These are the functions that handle initializing a BFD. + +@findex bfd_init +@subsubsection @code{bfd_init} +@strong{Synopsis} +@example +void bfd_init (void); +@end example +@strong{Description}@* +This routine must be called before any other BFD function to +initialize magical internal data structures. + diff --git a/contrib/binutils-2.17/bfd/doc/libbfd.texi b/contrib/binutils-2.17/bfd/doc/libbfd.texi new file mode 100644 index 0000000000..fef6e0e842 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/libbfd.texi @@ -0,0 +1,179 @@ +@section Implementation details + + +@subsection Internal functions + + +@strong{Description}@* +These routines are used within BFD. +They are not intended for export, but are documented here for +completeness. + +@findex bfd_write_bigendian_4byte_int +@subsubsection @code{bfd_write_bigendian_4byte_int} +@strong{Synopsis} +@example +bfd_boolean bfd_write_bigendian_4byte_int (bfd *, unsigned int); +@end example +@strong{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. + +@findex bfd_put_size +@subsubsection @code{bfd_put_size} +@findex bfd_get_size +@subsubsection @code{bfd_get_size} +@strong{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 @code{GET_WORD} +to either @code{bfd_get_32} or @code{bfd_get_64}. + +In the put routines, @var{val} must be a @code{bfd_vma}. 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 @code{lint} +or @code{gcc -Wall} from detecting sins such as passing a pointer. +To detect calling these with less than a @code{bfd_vma}, use +@code{gcc -Wconversion} on a host with 64 bit @code{bfd_vma}'s. +@example + +/* Byte swapping macros for user section data. */ + +#define bfd_put_8(abfd, val, ptr) \ + ((void) (*((unsigned char *) (ptr)) = (val) & 0xff)) +#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)) + +@end example + +@findex bfd_h_put_size +@subsubsection @code{bfd_h_put_size} +@strong{Description}@* +These macros have the same function as their @code{bfd_get_x} +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. +@example + +/* 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)) + +/* Aliases for the above, which should eventually go away. */ + +#define H_PUT_64 bfd_h_put_64 +#define H_PUT_32 bfd_h_put_32 +#define H_PUT_16 bfd_h_put_16 +#define H_PUT_8 bfd_h_put_8 +#define H_PUT_S64 bfd_h_put_signed_64 +#define H_PUT_S32 bfd_h_put_signed_32 +#define H_PUT_S16 bfd_h_put_signed_16 +#define H_PUT_S8 bfd_h_put_signed_8 +#define H_GET_64 bfd_h_get_64 +#define H_GET_32 bfd_h_get_32 +#define H_GET_16 bfd_h_get_16 +#define H_GET_8 bfd_h_get_8 +#define H_GET_S64 bfd_h_get_signed_64 +#define H_GET_S32 bfd_h_get_signed_32 +#define H_GET_S16 bfd_h_get_signed_16 +#define H_GET_S8 bfd_h_get_signed_8 + + +@end example + +@findex bfd_log2 +@subsubsection @code{bfd_log2} +@strong{Synopsis} +@example +unsigned int bfd_log2 (bfd_vma x); +@end example +@strong{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. + diff --git a/contrib/binutils-2.17/bfd/doc/linker.texi b/contrib/binutils-2.17/bfd/doc/linker.texi new file mode 100644 index 0000000000..8a55006a18 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/linker.texi @@ -0,0 +1,380 @@ +@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 @code{struct bfd_link_info} structure (defined in +@code{bfdlink.h}) 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 @code{linker.c}, and use the +header file @code{genlink.h}. As of this writing, the only back +ends which have implemented versions of these routines are +a.out (in @code{aoutx.h}) and ECOFF (in @code{ecoff.c}). 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 + +@node 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 @code{struct bfd_link_hash_table} described in +@code{bfdlink.c}. @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 @code{_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 @code{struct bfd_link_hash_table}. 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 relocatable +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 @code{struct bfd_link_hash_table}. The a.out linker +hash table is created by the function +@code{NAME(aout,link_hash_table_create)}; 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. + +@node 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 @code{_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 +@code{NAME(aout,link_add_symbols)}. + +@menu +* Differing file formats:: +* Adding symbols from an object file:: +* Adding symbols from an archive:: +@end menu + +@node 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 +@code{_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 +@code{_bfd_link_hash_table_create} vector. All the +@code{_bfd_link_add_symbols} function can assume about the hash +table is that it is derived from @code{struct +bfd_link_hash_table}. + +Sometimes the @code{_bfd_link_add_symbols} function must store +some information in the hash table entry to be used by the +@code{_bfd_final_link} function. In such a case the @code{creator} +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 @code{_bfd_final_link} routine must be prepared to handle a +hash entry without any extra information added by the +@code{_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 @code{ecoff_link_add_externals} for an example of how to +check the @code{creator} field before saving information (in this +case, the ECOFF external symbol debugging information) in a +hash table entry. + +@node 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 @code{_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 +@code{_bfd_generic_link_add_one_symbol}. The +@code{_bfd_link_add_symbols} routine is responsible for reading +all the symbols from the object file and passing the correct +information to @code{_bfd_generic_link_add_one_symbol}. + +The @code{_bfd_link_add_symbols} routine should not use +@code{bfd_canonicalize_symtab} to read the symbols. The point of +providing this routine is to avoid the overhead of converting +the symbols into generic @code{asymbol} structures. + +@findex _bfd_generic_link_add_one_symbol +@code{_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 @code{BSF_WEAK} or +@code{BSF_INDIRECT}. The section is a section in the object +file, or something like @code{bfd_und_section_ptr} for an undefined +symbol or @code{bfd_com_section_ptr} for a common symbol. + +If the @code{_bfd_final_link} routine is also going to need to +read the symbol information, the @code{_bfd_link_add_symbols} +routine should save it somewhere attached to the object file +BFD. However, the information should only be saved if the +@code{keep_memory} field of the @code{info} argument is TRUE, so +that the @code{-no-keep-memory} linker switch is effective. + +The a.out function which adds symbols from an object file is +@code{aout_link_add_object_symbols}, and most of the interesting +work is in @code{aout_link_add_symbols}. The latter saves +pointers to the hash tables entries created by +@code{_bfd_generic_link_add_one_symbol} indexed by symbol number, +so that the @code{_bfd_final_link} routine does not have to call +the hash table lookup routine to locate the entry. + +@node 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 @code{_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 +@code{add_archive_element} 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 +@code{_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. +@code{_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 +@code{_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 @code{add_archive_element} 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 +@code{_bfd_link_add_symbols} function. + +When the a.out @code{_bfd_link_add_symbols} function receives an +archive, it calls @code{_bfd_generic_link_add_archive_symbols} +passing @code{aout_link_check_archive_element} as the function +argument. @code{aout_link_check_archive_element} calls +@code{aout_link_check_ar_symbols}. 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 @code{add_archive_element} callback and then +@code{aout_link_check_archive_element} calls +@code{aout_link_add_symbols} to actually add the symbols to the +linker hash table. + +The ECOFF back end is unusual in that it does not normally +call @code{_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. + +@node 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 @code{_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 relocatable 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 @code{write_object_contents} 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 +@code{_bfd_final_link} routine is @code{NAME(aout,final_link)}. + +@menu +* Information provided by the linker:: +* Relocating the section contents:: +* Writing the symbol table:: +@end menu + +@node 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 @code{_bfd_final_link} entry point, +it sets up some data structures for the function to use. + +The @code{input_bfds} field of the @code{bfd_link_info} structure +will point to a list of all the input files included in the +link. These files are linked through the @code{link_next} field +of the @code{bfd} structure. + +Each section in the output file will have a list of +@code{link_order} structures attached to the @code{map_head.link_order} +field (the @code{link_order} structure is defined in +@code{bfdlink.h}). 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 relocatable object file. + +@node Relocating the section contents, Writing the symbol table, Information provided by the linker, Performing the Final Link +@subsubsection Relocating the section contents +The @code{_bfd_final_link} function should look through the +@code{link_order} structures attached to each section of the +output file. Each @code{link_order} structure should either be +handled specially, or it should be passed to the function +@code{_bfd_default_link_order} which will do the right thing +(@code{_bfd_default_link_order} is defined in @code{linker.c}). + +For efficiency, a @code{link_order} of type +@code{bfd_indirect_link_order} whose associated section belongs +to a BFD of the same format as the output BFD must be handled +specially. This type of @code{link_order} describes part of an +output section in terms of a section belonging to one of the +input files. The @code{_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 relocatable link, the +relocs themselves must also be modified and written out. + +@findex _bfd_relocate_contents +@findex _bfd_final_link_relocate +The functions @code{_bfd_relocate_contents} and +@code{_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 @code{reloc_howto_type} argument +which describes the relocation to perform. These functions +are defined in @code{reloc.c}. + +The a.out function which handles reading, relocating, and +writing section contents is @code{aout_link_input_section}. The +actual relocation is done in @code{aout_link_input_section_std} +and @code{aout_link_input_section_ext}. + +@node Writing the symbol table, , Relocating the section contents, Performing the Final Link +@subsubsection Writing the symbol table +The @code{_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 @code{strip} and @code{discard} fields of the +@code{bfd_link_info} structure. + +The local symbols of the input files will not have been +entered into the linker hash table. The @code{_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 @code{link_order} structures, or it may be +done by stepping through the @code{input_bfds} list. + +The @code{_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 @code{strip} field of the @code{bfd_link_info} structure +controls which symbols are written out. The possible values +are listed in @code{bfdlink.h}. If the value is @code{strip_some}, +then the @code{keep_hash} field of the @code{bfd_link_info} +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 @code{strip} field of the @code{bfd_link_info} structure +permits local symbols to be written out, the @code{discard} field +is used to further controls which local symbols are included +in the output file. If the value is @code{discard_l}, then all +local symbols which begin with a certain prefix are discarded; +this is controlled by the @code{bfd_is_local_label_name} entry point. + +The a.out backend handles symbols by calling +@code{aout_link_write_symbols} on each input BFD and then +traversing the global hash table with the function +@code{aout_link_write_other_symbol}. It builds a string table +while writing out the symbols, which is written to the output +file at the end of @code{NAME(aout,final_link)}. + +@findex bfd_link_split_section +@subsubsection @code{bfd_link_split_section} +@strong{Synopsis} +@example +bfd_boolean bfd_link_split_section (bfd *abfd, asection *sec); +@end example +@strong{Description}@* +Return nonzero if @var{sec} should be split during a +reloceatable or final link. +@example +#define bfd_link_split_section(abfd, sec) \ + BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec)) + +@end example + +@findex bfd_section_already_linked +@subsubsection @code{bfd_section_already_linked} +@strong{Synopsis} +@example +void bfd_section_already_linked (bfd *abfd, asection *sec); +@end example +@strong{Description}@* +Check if @var{sec} has been already linked during a reloceatable +or final link. +@example +#define bfd_section_already_linked(abfd, sec) \ + BFD_SEND (abfd, _section_already_linked, (abfd, sec)) + +@end example + diff --git a/contrib/binutils-2.17/bfd/doc/mmo.texi b/contrib/binutils-2.17/bfd/doc/mmo.texi new file mode 100644 index 0000000000..b0d726aad9 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/mmo.texi @@ -0,0 +1,365 @@ +@section mmo backend +The mmo object format is used exclusively together with Professor +Donald E.@: Knuth's educational 64-bit processor MMIX. The simulator +@command{mmix} which is available at +@url{http://www-cs-faculty.stanford.edu/~knuth/programs/mmix.tar.gz} +understands this format. That package also includes a combined +assembler and linker called @command{mmixal}. The mmo format has +no advantages feature-wise compared to e.g. ELF. It is a simple +non-relocatable object format with no support for archives or +debugging information, except for symbol value information and +line numbers (which is not yet implemented in BFD). See +@url{http://www-cs-faculty.stanford.edu/~knuth/mmix.html} for more +information about MMIX. The ELF format is used for intermediate +object files in the BFD implementation. + +@c We want to xref the symbol table node. A feature in "chew" +@c requires that "commands" do not contain spaces in the +@c arguments. Hence the hyphen in "Symbol-table". +@menu +* File layout:: +* Symbol-table:: +* mmo section mapping:: +@end menu + +@node File layout, Symbol-table, mmo, mmo +@subsection File layout +The mmo file contents is not partitioned into named sections as +with e.g.@: ELF. Memory areas is formed by specifying the +location of the data that follows. Only the memory area +@samp{0x0000@dots{}00} to @samp{0x01ff@dots{}ff} is executable, so +it is used for code (and constants) and the area +@samp{0x2000@dots{}00} to @samp{0x20ff@dots{}ff} is used for +writable data. @xref{mmo section mapping}. + +There is provision for specifying ``special data'' of 65536 +different types. We use type 80 (decimal), arbitrarily chosen the +same as the ELF @code{e_machine} number for MMIX, filling it with +section information normally found in ELF objects. @xref{mmo +section mapping}. + +Contents is entered as 32-bit words, xor:ed over previous +contents, always zero-initialized. A word that starts with the +byte @samp{0x98} forms a command called a @samp{lopcode}, where +the next byte distinguished between the thirteen lopcodes. The +two remaining bytes, called the @samp{Y} and @samp{Z} fields, or +the @samp{YZ} field (a 16-bit big-endian number), are used for +various purposes different for each lopcode. As documented in +@url{http://www-cs-faculty.stanford.edu/~knuth/mmixal-intro.ps.gz}, +the lopcodes are: + +@table @code +@item lop_quote +0x98000001. The next word is contents, regardless of whether it +starts with 0x98 or not. + +@item lop_loc +0x9801YYZZ, where @samp{Z} is 1 or 2. This is a location +directive, setting the location for the next data to the next +32-bit word (for @math{Z = 1}) or 64-bit word (for @math{Z = 2}), +plus @math{Y * 2^56}. Normally @samp{Y} is 0 for the text segment +and 2 for the data segment. + +@item lop_skip +0x9802YYZZ. Increase the current location by @samp{YZ} bytes. + +@item lop_fixo +0x9803YYZZ, where @samp{Z} is 1 or 2. Store the current location +as 64 bits into the location pointed to by the next 32-bit +(@math{Z = 1}) or 64-bit (@math{Z = 2}) word, plus @math{Y * +2^56}. + +@item lop_fixr +0x9804YYZZ. @samp{YZ} is stored into the current location plus +@math{2 - 4 * YZ}. + +@item lop_fixrx +0x980500ZZ. @samp{Z} is 16 or 24. A value @samp{L} derived from +the following 32-bit word are used in a manner similar to +@samp{YZ} in lop_fixr: it is xor:ed into the current location +minus @math{4 * L}. The first byte of the word is 0 or 1. If it +is 1, then @math{L = (@var{lowest 24 bits of word}) - 2^Z}, if 0, +then @math{L = (@var{lowest 24 bits of word})}. + +@item lop_file +0x9806YYZZ. @samp{Y} is the file number, @samp{Z} is count of +32-bit words. Set the file number to @samp{Y} and the line +counter to 0. The next @math{Z * 4} bytes contain the file name, +padded with zeros if the count is not a multiple of four. The +same @samp{Y} may occur multiple times, but @samp{Z} must be 0 for +all but the first occurrence. + +@item lop_line +0x9807YYZZ. @samp{YZ} is the line number. Together with +lop_file, it forms the source location for the next 32-bit word. +Note that for each non-lopcode 32-bit word, line numbers are +assumed incremented by one. + +@item lop_spec +0x9808YYZZ. @samp{YZ} is the type number. Data until the next +lopcode other than lop_quote forms special data of type @samp{YZ}. +@xref{mmo section mapping}. + +Other types than 80, (or type 80 with a content that does not +parse) is stored in sections named @code{.MMIX.spec_data.@var{n}} +where @var{n} is the @samp{YZ}-type. The flags for such a +sections say not to allocate or load the data. The vma is 0. +Contents of multiple occurrences of special data @var{n} is +concatenated to the data of the previous lop_spec @var{n}s. The +location in data or code at which the lop_spec occurred is lost. + +@item lop_pre +0x980901ZZ. The first lopcode in a file. The @samp{Z} field forms the +length of header information in 32-bit words, where the first word +tells the time in seconds since @samp{00:00:00 GMT Jan 1 1970}. + +@item lop_post +0x980a00ZZ. @math{Z > 32}. This lopcode follows after all +content-generating lopcodes in a program. The @samp{Z} field +denotes the value of @samp{rG} at the beginning of the program. +The following @math{256 - Z} big-endian 64-bit words are loaded +into global registers @samp{$G} @dots{} @samp{$255}. + +@item lop_stab +0x980b0000. The next-to-last lopcode in a program. Must follow +immediately after the lop_post lopcode and its data. After this +lopcode follows all symbols in a compressed format +(@pxref{Symbol-table}). + +@item lop_end +0x980cYYZZ. The last lopcode in a program. It must follow the +lop_stab lopcode and its data. The @samp{YZ} field contains the +number of 32-bit words of symbol table information after the +preceding lop_stab lopcode. +@end table + +Note that the lopcode "fixups"; @code{lop_fixr}, @code{lop_fixrx} and +@code{lop_fixo} are not generated by BFD, but are handled. They are +generated by @code{mmixal}. + +This trivial one-label, one-instruction file: + +@example + :Main TRAP 1,2,3 +@end example + +can be represented this way in mmo: + +@example + 0x98090101 - lop_pre, one 32-bit word with timestamp. + + 0x98010002 - lop_loc, text segment, using a 64-bit address. + Note that mmixal does not emit this for the file above. + 0x00000000 - Address, high 32 bits. + 0x00000000 - Address, low 32 bits. + 0x98060002 - lop_file, 2 32-bit words for file-name. + 0x74657374 - "test" + 0x2e730000 - ".s\0\0" + 0x98070001 - lop_line, line 1. + 0x00010203 - TRAP 1,2,3 + 0x980a00ff - lop_post, setting $255 to 0. + 0x00000000 + 0x00000000 + 0x980b0000 - lop_stab for ":Main" = 0, serial 1. + 0x203a4040 @xref{Symbol-table}. + 0x10404020 + 0x4d206120 + 0x69016e00 + 0x81000000 + 0x980c0005 - lop_end; symbol table contained five 32-bit words. +@end example +@node Symbol-table, mmo section mapping, File layout, mmo +@subsection Symbol table format +From mmixal.w (or really, the generated mmixal.tex) in +@url{http://www-cs-faculty.stanford.edu/~knuth/programs/mmix.tar.gz}): +``Symbols are stored and retrieved by means of a @samp{ternary +search trie}, following ideas of Bentley and Sedgewick. (See +ACM--SIAM Symp.@: on Discrete Algorithms @samp{8} (1997), 360--369; +R.@:Sedgewick, @samp{Algorithms in C} (Reading, Mass.@: +Addison--Wesley, 1998), @samp{15.4}.) Each trie node stores a +character, and there are branches to subtries for the cases where +a given character is less than, equal to, or greater than the +character in the trie. There also is a pointer to a symbol table +entry if a symbol ends at the current node.'' + +So it's a tree encoded as a stream of bytes. The stream of bytes +acts on a single virtual global symbol, adding and removing +characters and signalling complete symbol points. Here, we read +the stream and create symbols at the completion points. + +First, there's a control byte @code{m}. If any of the listed bits +in @code{m} is nonzero, we execute what stands at the right, in +the listed order: + +@example + (MMO3_LEFT) + 0x40 - Traverse left trie. + (Read a new command byte and recurse.) + + (MMO3_SYMBITS) + 0x2f - Read the next byte as a character and store it in the + current character position; increment character position. + Test the bits of @code{m}: + + (MMO3_WCHAR) + 0x80 - The character is 16-bit (so read another byte, + merge into current character. + + (MMO3_TYPEBITS) + 0xf - We have a complete symbol; parse the type, value + and serial number and do what should be done + with a symbol. The type and length information + is in j = (m & 0xf). + + (MMO3_REGQUAL_BITS) + j == 0xf: A register variable. The following + byte tells which register. + j <= 8: An absolute symbol. Read j bytes as the + big-endian number the symbol equals. + A j = 2 with two zero bytes denotes an + unknown symbol. + j > 8: As with j <= 8, but add (0x20 << 56) + to the value in the following j - 8 + bytes. + + Then comes the serial number, as a variant of + uleb128, but better named ubeb128: + Read bytes and shift the previous value left 7 + (multiply by 128). Add in the new byte, repeat + until a byte has bit 7 set. The serial number + is the computed value minus 128. + + (MMO3_MIDDLE) + 0x20 - Traverse middle trie. (Read a new command byte + and recurse.) Decrement character position. + + (MMO3_RIGHT) + 0x10 - Traverse right trie. (Read a new command byte and + recurse.) +@end example + +Let's look again at the @code{lop_stab} for the trivial file +(@pxref{File layout}). + +@example + 0x980b0000 - lop_stab for ":Main" = 0, serial 1. + 0x203a4040 + 0x10404020 + 0x4d206120 + 0x69016e00 + 0x81000000 +@end example + +This forms the trivial trie (note that the path between ``:'' and +``M'' is redundant): + +@example + 203a ":" + 40 / + 40 / + 10 \ + 40 / + 40 / + 204d "M" + 2061 "a" + 2069 "i" + 016e "n" is the last character in a full symbol, and + with a value represented in one byte. + 00 The value is 0. + 81 The serial number is 1. +@end example + +@node mmo section mapping, , Symbol-table, mmo +@subsection mmo section mapping +The implementation in BFD uses special data type 80 (decimal) to +encapsulate and describe named sections, containing e.g.@: debug +information. If needed, any datum in the encapsulation will be +quoted using lop_quote. First comes a 32-bit word holding the +number of 32-bit words containing the zero-terminated zero-padded +segment name. After the name there's a 32-bit word holding flags +describing the section type. Then comes a 64-bit big-endian word +with the section length (in bytes), then another with the section +start address. Depending on the type of section, the contents +might follow, zero-padded to 32-bit boundary. For a loadable +section (such as data or code), the contents might follow at some +later point, not necessarily immediately, as a lop_loc with the +same start address as in the section description, followed by the +contents. This in effect forms a descriptor that must be emitted +before the actual contents. Sections described this way must not +overlap. + +For areas that don't have such descriptors, synthetic sections are +formed by BFD. Consecutive contents in the two memory areas +@samp{0x0000@dots{}00} to @samp{0x01ff@dots{}ff} and +@samp{0x2000@dots{}00} to @samp{0x20ff@dots{}ff} are entered in +sections named @code{.text} and @code{.data} respectively. If an area +is not otherwise described, but would together with a neighboring +lower area be less than @samp{0x40000000} bytes long, it is joined +with the lower area and the gap is zero-filled. For other cases, +a new section is formed, named @code{.MMIX.sec.@var{n}}. Here, +@var{n} is a number, a running count through the mmo file, +starting at 0. + +A loadable section specified as: + +@example + .section secname,"ax" + TETRA 1,2,3,4,-1,-2009 + BYTE 80 +@end example + +and linked to address @samp{0x4}, is represented by the sequence: + +@example + 0x98080050 - lop_spec 80 + 0x00000002 - two 32-bit words for the section name + 0x7365636e - "secn" + 0x616d6500 - "ame\0" + 0x00000033 - flags CODE, READONLY, LOAD, ALLOC + 0x00000000 - high 32 bits of section length + 0x0000001c - section length is 28 bytes; 6 * 4 + 1 + alignment to 32 bits + 0x00000000 - high 32 bits of section address + 0x00000004 - section address is 4 + 0x98010002 - 64 bits with address of following data + 0x00000000 - high 32 bits of address + 0x00000004 - low 32 bits: data starts at address 4 + 0x00000001 - 1 + 0x00000002 - 2 + 0x00000003 - 3 + 0x00000004 - 4 + 0xffffffff - -1 + 0xfffff827 - -2009 + 0x50000000 - 80 as a byte, padded with zeros. +@end example + +Note that the lop_spec wrapping does not include the section +contents. Compare this to a non-loaded section specified as: + +@example + .section thirdsec + TETRA 200001,100002 + BYTE 38,40 +@end example + +This, when linked to address @samp{0x200000000000001c}, is +represented by: + +@example + 0x98080050 - lop_spec 80 + 0x00000002 - two 32-bit words for the section name + 0x7365636e - "thir" + 0x616d6500 - "dsec" + 0x00000010 - flag READONLY + 0x00000000 - high 32 bits of section length + 0x0000000c - section length is 12 bytes; 2 * 4 + 2 + alignment to 32 bits + 0x20000000 - high 32 bits of address + 0x0000001c - low 32 bits of address 0x200000000000001c + 0x00030d41 - 200001 + 0x000186a2 - 100002 + 0x26280000 - 38, 40 as bytes, padded with zeros +@end example + +For the latter example, the section contents must not be +loaded in memory, and is therefore specified as part of the +special data. The address is usually unimportant but might +provide information for e.g.@: the DWARF 2 debugging format. diff --git a/contrib/binutils-2.17/bfd/doc/opncls.texi b/contrib/binutils-2.17/bfd/doc/opncls.texi new file mode 100644 index 0000000000..6b47adfbb4 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/opncls.texi @@ -0,0 +1,365 @@ +@section Opening and closing BFDs + + +@subsection Functions for opening and closing + + +@findex bfd_fopen +@subsubsection @code{bfd_fopen} +@strong{Synopsis} +@example +bfd *bfd_fopen (const char *filename, const char *target, + const char *mode, int fd); +@end example +@strong{Description}@* +Open the file @var{filename} with the target @var{target}. +Return a pointer to the created BFD. If @var{fd} is not -1, +then @code{fdopen} is used to open the file; otherwise, @code{fopen} +is used. @var{mode} is passed directly to @code{fopen} or +@code{fdopen}. + +Calls @code{bfd_find_target}, so @var{target} is interpreted as by +that function. + +The new BFD is marked as cacheable iff @var{fd} is -1. + +If @code{NULL} is returned then an error has occured. Possible errors +are @code{bfd_error_no_memory}, @code{bfd_error_invalid_target} or +@code{system_call} error. + +@findex bfd_openr +@subsubsection @code{bfd_openr} +@strong{Synopsis} +@example +bfd *bfd_openr (const char *filename, const char *target); +@end example +@strong{Description}@* +Open the file @var{filename} (using @code{fopen}) with the target +@var{target}. Return a pointer to the created BFD. + +Calls @code{bfd_find_target}, so @var{target} is interpreted as by +that function. + +If @code{NULL} is returned then an error has occured. Possible errors +are @code{bfd_error_no_memory}, @code{bfd_error_invalid_target} or +@code{system_call} error. + +@findex bfd_fdopenr +@subsubsection @code{bfd_fdopenr} +@strong{Synopsis} +@example +bfd *bfd_fdopenr (const char *filename, const char *target, int fd); +@end example +@strong{Description}@* +@code{bfd_fdopenr} is to @code{bfd_fopenr} much like @code{fdopen} is to +@code{fopen}. It opens a BFD on a file already described by the +@var{fd} supplied. + +When the file is later @code{bfd_close}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 caching; the file descriptor will remain open +until @code{bfd_close}, and will not be affected by BFD operations +on other files. + +Possible errors are @code{bfd_error_no_memory}, +@code{bfd_error_invalid_target} and @code{bfd_error_system_call}. + +@findex bfd_openstreamr +@subsubsection @code{bfd_openstreamr} +@strong{Synopsis} +@example +bfd *bfd_openstreamr (const char *, const char *, void *); +@end example +@strong{Description}@* +Open a BFD for read access on an existing stdio stream. When +the BFD is passed to @code{bfd_close}, the stream will be closed. + +@findex bfd_openr_iovec +@subsubsection @code{bfd_openr_iovec} +@strong{Synopsis} +@example +bfd *bfd_openr_iovec (const char *filename, const char *target, + void *(*open) (struct bfd *nbfd, + void *open_closure), + void *open_closure, + file_ptr (*pread) (struct bfd *nbfd, + void *stream, + void *buf, + file_ptr nbytes, + file_ptr offset), + int (*close) (struct bfd *nbfd, + void *stream)); +@end example +@strong{Description}@* +Create and return a BFD backed by a read-only @var{stream}. +The @var{stream} is created using @var{open}, accessed using +@var{pread} and destroyed using @var{close}. + +Calls @code{bfd_find_target}, so @var{target} is interpreted as by +that function. + +Calls @var{open} (which can call @code{bfd_zalloc} and +@code{bfd_get_filename}) to obtain the read-only stream backing +the BFD. @var{open} either succeeds returning the +non-@code{NULL} @var{stream}, or fails returning @code{NULL} +(setting @code{bfd_error}). + +Calls @var{pread} to request @var{nbytes} of data from +@var{stream} starting at @var{offset} (e.g., via a call to +@code{bfd_read}). @var{pread} either succeeds returning the +number of bytes read (which can be less than @var{nbytes} when +end-of-file), or fails returning -1 (setting @code{bfd_error}). + +Calls @var{close} when the BFD is later closed using +@code{bfd_close}. @var{close} either succeeds returning 0, or +fails returning -1 (setting @code{bfd_error}). + +If @code{bfd_openr_iovec} returns @code{NULL} then an error has +occurred. Possible errors are @code{bfd_error_no_memory}, +@code{bfd_error_invalid_target} and @code{bfd_error_system_call}. + +@findex bfd_openw +@subsubsection @code{bfd_openw} +@strong{Synopsis} +@example +bfd *bfd_openw (const char *filename, const char *target); +@end example +@strong{Description}@* +Create a BFD, associated with file @var{filename}, using the +file format @var{target}, and return a pointer to it. + +Possible errors are @code{bfd_error_system_call}, @code{bfd_error_no_memory}, +@code{bfd_error_invalid_target}. + +@findex bfd_close +@subsubsection @code{bfd_close} +@strong{Synopsis} +@example +bfd_boolean bfd_close (bfd *abfd); +@end example +@strong{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 @code{chmod} 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 @code{bfd_fdopenr}). + +@strong{Returns}@* +@code{TRUE} is returned if all is ok, otherwise @code{FALSE}. + +@findex bfd_close_all_done +@subsubsection @code{bfd_close_all_done} +@strong{Synopsis} +@example +bfd_boolean bfd_close_all_done (bfd *); +@end example +@strong{Description}@* +Close a BFD. Differs from @code{bfd_close} 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 @code{chmod} is called +to mark it as such. + +All memory attached to the BFD is released. + +@strong{Returns}@* +@code{TRUE} is returned if all is ok, otherwise @code{FALSE}. + +@findex bfd_create +@subsubsection @code{bfd_create} +@strong{Synopsis} +@example +bfd *bfd_create (const char *filename, bfd *templ); +@end example +@strong{Description}@* +Create a new BFD in the manner of @code{bfd_openw}, but without +opening a file. The new BFD takes the target from the target +used by @var{template}. The format is always set to @code{bfd_object}. + +@findex bfd_make_writable +@subsubsection @code{bfd_make_writable} +@strong{Synopsis} +@example +bfd_boolean bfd_make_writable (bfd *abfd); +@end example +@strong{Description}@* +Takes a BFD as created by @code{bfd_create} and converts it +into one like as returned by @code{bfd_openw}. It does this +by converting the BFD to BFD_IN_MEMORY. It's assumed that +you will call @code{bfd_make_readable} on this bfd later. + +@strong{Returns}@* +@code{TRUE} is returned if all is ok, otherwise @code{FALSE}. + +@findex bfd_make_readable +@subsubsection @code{bfd_make_readable} +@strong{Synopsis} +@example +bfd_boolean bfd_make_readable (bfd *abfd); +@end example +@strong{Description}@* +Takes a BFD as created by @code{bfd_create} and +@code{bfd_make_writable} and converts it into one like as +returned by @code{bfd_openr}. It does this by writing the +contents out to the memory buffer, then reversing the +direction. + +@strong{Returns}@* +@code{TRUE} is returned if all is ok, otherwise @code{FALSE}. + +@findex bfd_alloc +@subsubsection @code{bfd_alloc} +@strong{Synopsis} +@example +void *bfd_alloc (bfd *abfd, bfd_size_type wanted); +@end example +@strong{Description}@* +Allocate a block of @var{wanted} bytes of memory attached to +@code{abfd} and return a pointer to it. + +@findex bfd_alloc2 +@subsubsection @code{bfd_alloc2} +@strong{Synopsis} +@example +void *bfd_alloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size); +@end example +@strong{Description}@* +Allocate a block of @var{nmemb} elements of @var{size} bytes each +of memory attached to @code{abfd} and return a pointer to it. + +@findex bfd_zalloc +@subsubsection @code{bfd_zalloc} +@strong{Synopsis} +@example +void *bfd_zalloc (bfd *abfd, bfd_size_type wanted); +@end example +@strong{Description}@* +Allocate a block of @var{wanted} bytes of zeroed memory +attached to @code{abfd} and return a pointer to it. + +@findex bfd_zalloc2 +@subsubsection @code{bfd_zalloc2} +@strong{Synopsis} +@example +void *bfd_zalloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size); +@end example +@strong{Description}@* +Allocate a block of @var{nmemb} elements of @var{size} bytes each +of zeroed memory attached to @code{abfd} and return a pointer to it. + +@findex bfd_calc_gnu_debuglink_crc32 +@subsubsection @code{bfd_calc_gnu_debuglink_crc32} +@strong{Synopsis} +@example +unsigned long bfd_calc_gnu_debuglink_crc32 + (unsigned long crc, const unsigned char *buf, bfd_size_type len); +@end example +@strong{Description}@* +Computes a CRC value as used in the .gnu_debuglink section. +Advances the previously computed @var{crc} value by computing +and adding in the crc32 for @var{len} bytes of @var{buf}. + +@strong{Returns}@* +Return the updated CRC32 value. + +@findex get_debug_link_info +@subsubsection @code{get_debug_link_info} +@strong{Synopsis} +@example +char *get_debug_link_info (bfd *abfd, unsigned long *crc32_out); +@end example +@strong{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}. + +@findex separate_debug_file_exists +@subsubsection @code{separate_debug_file_exists} +@strong{Synopsis} +@example +bfd_boolean separate_debug_file_exists + (char *name, unsigned long crc32); +@end example +@strong{Description}@* +Checks to see if @var{name} is a file and if its contents +match @var{crc32}. + +@findex find_separate_debug_file +@subsubsection @code{find_separate_debug_file} +@strong{Synopsis} +@example +char *find_separate_debug_file (bfd *abfd); +@end example +@strong{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. + +@findex bfd_follow_gnu_debuglink +@subsubsection @code{bfd_follow_gnu_debuglink} +@strong{Synopsis} +@example +char *bfd_follow_gnu_debuglink (bfd *abfd, const char *dir); +@end example +@strong{Description}@* +Takes a BFD and searches it for a .gnu_debuglink section. If this +section is found, it examines the section for the name and checksum +of a '.debug' file containing auxiliary debugging information. It +then searches the filesystem for this .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, it will search a default path configured into +libbfd at build time. [XXX this feature is not currently +implemented]. + +@strong{Returns}@* +@code{NULL} 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. + +@findex bfd_create_gnu_debuglink_section +@subsubsection @code{bfd_create_gnu_debuglink_section} +@strong{Synopsis} +@example +struct bfd_section *bfd_create_gnu_debuglink_section + (bfd *abfd, const char *filename); +@end example +@strong{Description}@* +Takes a @var{BFD} and adds a .gnu_debuglink section to it. The section is sized +to be big enough to contain a link to the specified @var{filename}. + +@strong{Returns}@* +A pointer to the new section is returned if all is ok. Otherwise @code{NULL} is +returned and bfd_error is set. + +@findex bfd_fill_in_gnu_debuglink_section +@subsubsection @code{bfd_fill_in_gnu_debuglink_section} +@strong{Synopsis} +@example +bfd_boolean bfd_fill_in_gnu_debuglink_section + (bfd *abfd, struct bfd_section *sect, const char *filename); +@end example +@strong{Description}@* +Takes a @var{BFD} and containing a .gnu_debuglink section @var{SECT} +and fills in the contents of the section to contain a link to the +specified @var{filename}. The filename should be relative to the +current directory. + +@strong{Returns}@* +@code{TRUE} is returned if all is ok. Otherwise @code{FALSE} is returned +and bfd_error is set. + diff --git a/contrib/binutils-2.17/bfd/doc/reloc.texi b/contrib/binutils-2.17/bfd/doc/reloc.texi new file mode 100644 index 0000000000..0540be8625 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/reloc.texi @@ -0,0 +1,2494 @@ +@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 @code{bfd_perform_relocation} 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 @code{struct reloc_cache_entry} for each relocation +in a particular section, and fill in the right bits of the structures. + +@menu +* typedef arelent:: +* howto manager:: +@end menu + + +@node typedef arelent, howto manager, Relocations, Relocations +@subsection typedef arelent +This is the structure of a relocation entry: + + +@example + +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 bfd_symbol **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; + +@end example +@strong{Description}@* +Here is a description of each of the fields within an @code{arelent}: + +@itemize @bullet + +@item +@code{sym_ptr_ptr} +@end itemize +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 +@code{canonicalize_symtab} 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. + +@itemize @bullet + +@item +@code{address} +@end itemize +The @code{address} 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. + +@itemize @bullet + +@item +@code{addend} +@end itemize +The @code{addend} 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: + +@example + char foo[]; + main() + @{ + return foo[0x12345678]; + @} +@end example + +Could be compiled into: + +@example + linkw fp,#-4 + moveb @@#12345678,d0 + extbl d0 + unlk fp + rts +@end example + +This could create a reloc pointing to @code{foo}, but leave the +offset in the data, something like: + +@example +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 +@end example + +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: + +@example + or.u r13,r0,hi16(_foo+0x12345678) + ld.b r2,r13,lo16(_foo+0x12345678) + jmp r1 +@end example + +This should create two relocs, both pointing to @code{_foo}, and with +0x12340000 in their addend field. The data would consist of: + +@example +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 +@end example + +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 @code{_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. + +@example + save %sp,-112,%sp + sethi %hi(_foo+0x12345678),%g2 + ldsb [%g2+%lo(_foo+0x12345678)],%i0 + ret + restore +@end example + +Both relocs contain a pointer to @code{foo}, and the offsets +contain junk. + +@example +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 +@end example + +@itemize @bullet + +@item +@code{howto} +@end itemize +The @code{howto} 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 @code{enum complain_overflow} +Indicates what sort of overflow checking should be done when +performing a relocation. + + +@example + +enum complain_overflow +@{ + /* Do not complain on overflow. */ + complain_overflow_dont, + + /* Complain if the value overflows when considered as a signed + number one bit larger than the field. ie. A bitfield of N bits + is allowed to represent -2**n to 2**n-1. */ + complain_overflow_bitfield, + + /* Complain if the value overflows when considered as a signed + number. */ + complain_overflow_signed, + + /* Complain if the value overflows when considered as an + unsigned number. */ + complain_overflow_unsigned +@}; +@end example +@subsubsection @code{reloc_howto_type} +The @code{reloc_howto_type} is a structure which contains all the +information that libbfd needs to know to tie up a back end's data. + + +@example +struct bfd_symbol; /* 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 accommodated (e.g., i960 callj + instructions). */ + bfd_reloc_status_type (*special_function) + (bfd *, arelent *, struct bfd_symbol *, void *, 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; +@}; + +@end example +@findex The HOWTO Macro +@subsubsection @code{The HOWTO Macro} +@strong{Description}@* +The HOWTO define is horrible and will go away. +@example +#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 @} +@end example + +@strong{Description}@* +And will be replaced with the totally magic way. But for the +moment, we are compatible, so do it this way. +@example +#define NEWHOWTO(FUNCTION, NAME, SIZE, REL, IN) \ + HOWTO (0, 0, SIZE, 0, REL, 0, complain_overflow_dont, FUNCTION, \ + NAME, FALSE, 0, 0, IN) + +@end example + +@strong{Description}@* +This is used to fill in an empty howto entry in an array. +@example +#define EMPTY_HOWTO(C) \ + HOWTO ((C), 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, \ + NULL, FALSE, 0, 0, FALSE) + +@end example + +@strong{Description}@* +Helper routine to turn a symbol into a relocation value. +@example +#define HOWTO_PREPARE(relocation, symbol) \ + @{ \ + if (symbol != NULL) \ + @{ \ + if (bfd_is_com_section (symbol->section)) \ + @{ \ + relocation = 0; \ + @} \ + else \ + @{ \ + relocation = symbol->value; \ + @} \ + @} \ + @} + +@end example + +@findex bfd_get_reloc_size +@subsubsection @code{bfd_get_reloc_size} +@strong{Synopsis} +@example +unsigned int bfd_get_reloc_size (reloc_howto_type *); +@end example +@strong{Description}@* +For a reloc_howto_type that operates on a fixed number of bytes, +this returns the number of bytes operated on. + +@findex arelent_chain +@subsubsection @code{arelent_chain} +@strong{Description}@* +How relocs are tied together in an @code{asection}: +@example +typedef struct relent_chain +@{ + arelent relent; + struct relent_chain *next; +@} +arelent_chain; + +@end example + +@findex bfd_check_overflow +@subsubsection @code{bfd_check_overflow} +@strong{Synopsis} +@example +bfd_reloc_status_type bfd_check_overflow + (enum complain_overflow how, + unsigned int bitsize, + unsigned int rightshift, + unsigned int addrsize, + bfd_vma relocation); +@end example +@strong{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}. + +@findex bfd_perform_relocation +@subsubsection @code{bfd_perform_relocation} +@strong{Synopsis} +@example +bfd_reloc_status_type bfd_perform_relocation + (bfd *abfd, + arelent *reloc_entry, + void *data, + asection *input_section, + bfd *output_bfd, + char **error_message); +@end example +@strong{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}. + +@findex bfd_install_relocation +@subsubsection @code{bfd_install_relocation} +@strong{Synopsis} +@example +bfd_reloc_status_type bfd_install_relocation + (bfd *abfd, + arelent *reloc_entry, + void *data, bfd_vma data_start, + asection *input_section, + char **error_message); +@end example +@strong{Description}@* +This looks remarkably like @code{bfd_perform_relocation}, 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. + + +@node howto manager, , typedef arelent, Relocations +@subsection 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. + +@findex bfd_reloc_code_type +@subsubsection @code{bfd_reloc_code_type} +@strong{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 @code{bfd_reloc_type_lookup}, 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. + +Here are the possible values for @code{enum bfd_reloc_code_real}: + +@deffn {} BFD_RELOC_64 +@deffnx {} BFD_RELOC_32 +@deffnx {} BFD_RELOC_26 +@deffnx {} BFD_RELOC_24 +@deffnx {} BFD_RELOC_16 +@deffnx {} BFD_RELOC_14 +@deffnx {} BFD_RELOC_8 +Basic absolute relocations of N bits. +@end deffn +@deffn {} BFD_RELOC_64_PCREL +@deffnx {} BFD_RELOC_32_PCREL +@deffnx {} BFD_RELOC_24_PCREL +@deffnx {} BFD_RELOC_16_PCREL +@deffnx {} BFD_RELOC_12_PCREL +@deffnx {} BFD_RELOC_8_PCREL +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. +@end deffn +@deffn {} BFD_RELOC_32_SECREL +Section relative relocations. Some targets need this for DWARF2. +@end deffn +@deffn {} BFD_RELOC_32_GOT_PCREL +@deffnx {} BFD_RELOC_16_GOT_PCREL +@deffnx {} BFD_RELOC_8_GOT_PCREL +@deffnx {} BFD_RELOC_32_GOTOFF +@deffnx {} BFD_RELOC_16_GOTOFF +@deffnx {} BFD_RELOC_LO16_GOTOFF +@deffnx {} BFD_RELOC_HI16_GOTOFF +@deffnx {} BFD_RELOC_HI16_S_GOTOFF +@deffnx {} BFD_RELOC_8_GOTOFF +@deffnx {} BFD_RELOC_64_PLT_PCREL +@deffnx {} BFD_RELOC_32_PLT_PCREL +@deffnx {} BFD_RELOC_24_PLT_PCREL +@deffnx {} BFD_RELOC_16_PLT_PCREL +@deffnx {} BFD_RELOC_8_PLT_PCREL +@deffnx {} BFD_RELOC_64_PLTOFF +@deffnx {} BFD_RELOC_32_PLTOFF +@deffnx {} BFD_RELOC_16_PLTOFF +@deffnx {} BFD_RELOC_LO16_PLTOFF +@deffnx {} BFD_RELOC_HI16_PLTOFF +@deffnx {} BFD_RELOC_HI16_S_PLTOFF +@deffnx {} BFD_RELOC_8_PLTOFF +For ELF. +@end deffn +@deffn {} BFD_RELOC_68K_GLOB_DAT +@deffnx {} BFD_RELOC_68K_JMP_SLOT +@deffnx {} BFD_RELOC_68K_RELATIVE +Relocations used by 68K ELF. +@end deffn +@deffn {} BFD_RELOC_32_BASEREL +@deffnx {} BFD_RELOC_16_BASEREL +@deffnx {} BFD_RELOC_LO16_BASEREL +@deffnx {} BFD_RELOC_HI16_BASEREL +@deffnx {} BFD_RELOC_HI16_S_BASEREL +@deffnx {} BFD_RELOC_8_BASEREL +@deffnx {} BFD_RELOC_RVA +Linkage-table relative. +@end deffn +@deffn {} BFD_RELOC_8_FFnn +Absolute 8-bit relocation, but used to form an address like 0xFFnn. +@end deffn +@deffn {} BFD_RELOC_32_PCREL_S2 +@deffnx {} BFD_RELOC_16_PCREL_S2 +@deffnx {} BFD_RELOC_23_PCREL_S2 +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. +@end deffn +@deffn {} BFD_RELOC_HI22 +@deffnx {} BFD_RELOC_LO10 +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. +@end deffn +@deffn {} BFD_RELOC_GPREL16 +@deffnx {} BFD_RELOC_GPREL32 +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. +@end deffn +@deffn {} BFD_RELOC_I960_CALLJ +Reloc types used for i960/b.out. +@end deffn +@deffn {} BFD_RELOC_NONE +@deffnx {} BFD_RELOC_SPARC_WDISP22 +@deffnx {} BFD_RELOC_SPARC22 +@deffnx {} BFD_RELOC_SPARC13 +@deffnx {} BFD_RELOC_SPARC_GOT10 +@deffnx {} BFD_RELOC_SPARC_GOT13 +@deffnx {} BFD_RELOC_SPARC_GOT22 +@deffnx {} BFD_RELOC_SPARC_PC10 +@deffnx {} BFD_RELOC_SPARC_PC22 +@deffnx {} BFD_RELOC_SPARC_WPLT30 +@deffnx {} BFD_RELOC_SPARC_COPY +@deffnx {} BFD_RELOC_SPARC_GLOB_DAT +@deffnx {} BFD_RELOC_SPARC_JMP_SLOT +@deffnx {} BFD_RELOC_SPARC_RELATIVE +@deffnx {} BFD_RELOC_SPARC_UA16 +@deffnx {} BFD_RELOC_SPARC_UA32 +@deffnx {} BFD_RELOC_SPARC_UA64 +SPARC ELF relocations. There is probably some overlap with other +relocation types already defined. +@end deffn +@deffn {} BFD_RELOC_SPARC_BASE13 +@deffnx {} BFD_RELOC_SPARC_BASE22 +I think these are specific to SPARC a.out (e.g., Sun 4). +@end deffn +@deffn {} BFD_RELOC_SPARC_64 +@deffnx {} BFD_RELOC_SPARC_10 +@deffnx {} BFD_RELOC_SPARC_11 +@deffnx {} BFD_RELOC_SPARC_OLO10 +@deffnx {} BFD_RELOC_SPARC_HH22 +@deffnx {} BFD_RELOC_SPARC_HM10 +@deffnx {} BFD_RELOC_SPARC_LM22 +@deffnx {} BFD_RELOC_SPARC_PC_HH22 +@deffnx {} BFD_RELOC_SPARC_PC_HM10 +@deffnx {} BFD_RELOC_SPARC_PC_LM22 +@deffnx {} BFD_RELOC_SPARC_WDISP16 +@deffnx {} BFD_RELOC_SPARC_WDISP19 +@deffnx {} BFD_RELOC_SPARC_7 +@deffnx {} BFD_RELOC_SPARC_6 +@deffnx {} BFD_RELOC_SPARC_5 +@deffnx {} BFD_RELOC_SPARC_DISP64 +@deffnx {} BFD_RELOC_SPARC_PLT32 +@deffnx {} BFD_RELOC_SPARC_PLT64 +@deffnx {} BFD_RELOC_SPARC_HIX22 +@deffnx {} BFD_RELOC_SPARC_LOX10 +@deffnx {} BFD_RELOC_SPARC_H44 +@deffnx {} BFD_RELOC_SPARC_M44 +@deffnx {} BFD_RELOC_SPARC_L44 +@deffnx {} BFD_RELOC_SPARC_REGISTER +SPARC64 relocations +@end deffn +@deffn {} BFD_RELOC_SPARC_REV32 +SPARC little endian relocation +@end deffn +@deffn {} BFD_RELOC_SPARC_TLS_GD_HI22 +@deffnx {} BFD_RELOC_SPARC_TLS_GD_LO10 +@deffnx {} BFD_RELOC_SPARC_TLS_GD_ADD +@deffnx {} BFD_RELOC_SPARC_TLS_GD_CALL +@deffnx {} BFD_RELOC_SPARC_TLS_LDM_HI22 +@deffnx {} BFD_RELOC_SPARC_TLS_LDM_LO10 +@deffnx {} BFD_RELOC_SPARC_TLS_LDM_ADD +@deffnx {} BFD_RELOC_SPARC_TLS_LDM_CALL +@deffnx {} BFD_RELOC_SPARC_TLS_LDO_HIX22 +@deffnx {} BFD_RELOC_SPARC_TLS_LDO_LOX10 +@deffnx {} BFD_RELOC_SPARC_TLS_LDO_ADD +@deffnx {} BFD_RELOC_SPARC_TLS_IE_HI22 +@deffnx {} BFD_RELOC_SPARC_TLS_IE_LO10 +@deffnx {} BFD_RELOC_SPARC_TLS_IE_LD +@deffnx {} BFD_RELOC_SPARC_TLS_IE_LDX +@deffnx {} BFD_RELOC_SPARC_TLS_IE_ADD +@deffnx {} BFD_RELOC_SPARC_TLS_LE_HIX22 +@deffnx {} BFD_RELOC_SPARC_TLS_LE_LOX10 +@deffnx {} BFD_RELOC_SPARC_TLS_DTPMOD32 +@deffnx {} BFD_RELOC_SPARC_TLS_DTPMOD64 +@deffnx {} BFD_RELOC_SPARC_TLS_DTPOFF32 +@deffnx {} BFD_RELOC_SPARC_TLS_DTPOFF64 +@deffnx {} BFD_RELOC_SPARC_TLS_TPOFF32 +@deffnx {} BFD_RELOC_SPARC_TLS_TPOFF64 +SPARC TLS relocations +@end deffn +@deffn {} BFD_RELOC_ALPHA_GPDISP_HI16 +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). +@end deffn +@deffn {} BFD_RELOC_ALPHA_GPDISP_LO16 +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. +@end deffn +@deffn {} BFD_RELOC_ALPHA_GPDISP +The ELF GPDISP relocation is exactly the same as the GPDISP_HI16 +relocation except that there is no accompanying GPDISP_LO16 +relocation. +@end deffn +@deffn {} BFD_RELOC_ALPHA_LITERAL +@deffnx {} BFD_RELOC_ALPHA_ELF_LITERAL +@deffnx {} BFD_RELOC_ALPHA_LITUSE +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) +@end deffn +@deffn {} BFD_RELOC_ALPHA_HINT +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. +@end deffn +@deffn {} BFD_RELOC_ALPHA_LINKAGE +The LINKAGE relocation outputs a linkage pair in the object file, +which is filled by the linker. +@end deffn +@deffn {} BFD_RELOC_ALPHA_CODEADDR +The CODEADDR relocation outputs a STO_CA in the object file, +which is filled by the linker. +@end deffn +@deffn {} BFD_RELOC_ALPHA_GPREL_HI16 +@deffnx {} BFD_RELOC_ALPHA_GPREL_LO16 +The GPREL_HI/LO relocations together form a 32-bit offset from the +GP register. +@end deffn +@deffn {} BFD_RELOC_ALPHA_BRSGP +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. +@end deffn +@deffn {} BFD_RELOC_ALPHA_TLSGD +@deffnx {} BFD_RELOC_ALPHA_TLSLDM +@deffnx {} BFD_RELOC_ALPHA_DTPMOD64 +@deffnx {} BFD_RELOC_ALPHA_GOTDTPREL16 +@deffnx {} BFD_RELOC_ALPHA_DTPREL64 +@deffnx {} BFD_RELOC_ALPHA_DTPREL_HI16 +@deffnx {} BFD_RELOC_ALPHA_DTPREL_LO16 +@deffnx {} BFD_RELOC_ALPHA_DTPREL16 +@deffnx {} BFD_RELOC_ALPHA_GOTTPREL16 +@deffnx {} BFD_RELOC_ALPHA_TPREL64 +@deffnx {} BFD_RELOC_ALPHA_TPREL_HI16 +@deffnx {} BFD_RELOC_ALPHA_TPREL_LO16 +@deffnx {} BFD_RELOC_ALPHA_TPREL16 +Alpha thread-local storage relocations. +@end deffn +@deffn {} BFD_RELOC_MIPS_JMP +Bits 27..2 of the relocation address shifted right 2 bits; +simple reloc otherwise. +@end deffn +@deffn {} BFD_RELOC_MIPS16_JMP +The MIPS16 jump instruction. +@end deffn +@deffn {} BFD_RELOC_MIPS16_GPREL +MIPS16 GP relative reloc. +@end deffn +@deffn {} BFD_RELOC_HI16 +High 16 bits of 32-bit value; simple reloc. +@end deffn +@deffn {} BFD_RELOC_HI16_S +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. +@end deffn +@deffn {} BFD_RELOC_LO16 +Low 16 bits. +@end deffn +@deffn {} BFD_RELOC_HI16_PCREL +High 16 bits of 32-bit pc-relative value +@end deffn +@deffn {} BFD_RELOC_HI16_S_PCREL +High 16 bits of 32-bit pc-relative value, adjusted +@end deffn +@deffn {} BFD_RELOC_LO16_PCREL +Low 16 bits of pc-relative value +@end deffn +@deffn {} BFD_RELOC_MIPS16_HI16 +MIPS16 high 16 bits of 32-bit value. +@end deffn +@deffn {} BFD_RELOC_MIPS16_HI16_S +MIPS16 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. +@end deffn +@deffn {} BFD_RELOC_MIPS16_LO16 +MIPS16 low 16 bits. +@end deffn +@deffn {} BFD_RELOC_MIPS_LITERAL +Relocation against a MIPS literal section. +@end deffn +@deffn {} BFD_RELOC_MIPS_GOT16 +@deffnx {} BFD_RELOC_MIPS_CALL16 +@deffnx {} BFD_RELOC_MIPS_GOT_HI16 +@deffnx {} BFD_RELOC_MIPS_GOT_LO16 +@deffnx {} BFD_RELOC_MIPS_CALL_HI16 +@deffnx {} BFD_RELOC_MIPS_CALL_LO16 +@deffnx {} BFD_RELOC_MIPS_SUB +@deffnx {} BFD_RELOC_MIPS_GOT_PAGE +@deffnx {} BFD_RELOC_MIPS_GOT_OFST +@deffnx {} BFD_RELOC_MIPS_GOT_DISP +@deffnx {} BFD_RELOC_MIPS_SHIFT5 +@deffnx {} BFD_RELOC_MIPS_SHIFT6 +@deffnx {} BFD_RELOC_MIPS_INSERT_A +@deffnx {} BFD_RELOC_MIPS_INSERT_B +@deffnx {} BFD_RELOC_MIPS_DELETE +@deffnx {} BFD_RELOC_MIPS_HIGHEST +@deffnx {} BFD_RELOC_MIPS_HIGHER +@deffnx {} BFD_RELOC_MIPS_SCN_DISP +@deffnx {} BFD_RELOC_MIPS_REL16 +@deffnx {} BFD_RELOC_MIPS_RELGOT +@deffnx {} BFD_RELOC_MIPS_JALR +@deffnx {} BFD_RELOC_MIPS_TLS_DTPMOD32 +@deffnx {} BFD_RELOC_MIPS_TLS_DTPREL32 +@deffnx {} BFD_RELOC_MIPS_TLS_DTPMOD64 +@deffnx {} BFD_RELOC_MIPS_TLS_DTPREL64 +@deffnx {} BFD_RELOC_MIPS_TLS_GD +@deffnx {} BFD_RELOC_MIPS_TLS_LDM +@deffnx {} BFD_RELOC_MIPS_TLS_DTPREL_HI16 +@deffnx {} BFD_RELOC_MIPS_TLS_DTPREL_LO16 +@deffnx {} BFD_RELOC_MIPS_TLS_GOTTPREL +@deffnx {} BFD_RELOC_MIPS_TLS_TPREL32 +@deffnx {} BFD_RELOC_MIPS_TLS_TPREL64 +@deffnx {} BFD_RELOC_MIPS_TLS_TPREL_HI16 +@deffnx {} BFD_RELOC_MIPS_TLS_TPREL_LO16 +MIPS ELF relocations. +@end deffn +@deffn {} BFD_RELOC_MIPS_COPY +@deffnx {} BFD_RELOC_MIPS_JUMP_SLOT +MIPS ELF relocations (VxWorks extensions). +@end deffn +@deffn {} BFD_RELOC_FRV_LABEL16 +@deffnx {} BFD_RELOC_FRV_LABEL24 +@deffnx {} BFD_RELOC_FRV_LO16 +@deffnx {} BFD_RELOC_FRV_HI16 +@deffnx {} BFD_RELOC_FRV_GPREL12 +@deffnx {} BFD_RELOC_FRV_GPRELU12 +@deffnx {} BFD_RELOC_FRV_GPREL32 +@deffnx {} BFD_RELOC_FRV_GPRELHI +@deffnx {} BFD_RELOC_FRV_GPRELLO +@deffnx {} BFD_RELOC_FRV_GOT12 +@deffnx {} BFD_RELOC_FRV_GOTHI +@deffnx {} BFD_RELOC_FRV_GOTLO +@deffnx {} BFD_RELOC_FRV_FUNCDESC +@deffnx {} BFD_RELOC_FRV_FUNCDESC_GOT12 +@deffnx {} BFD_RELOC_FRV_FUNCDESC_GOTHI +@deffnx {} BFD_RELOC_FRV_FUNCDESC_GOTLO +@deffnx {} BFD_RELOC_FRV_FUNCDESC_VALUE +@deffnx {} BFD_RELOC_FRV_FUNCDESC_GOTOFF12 +@deffnx {} BFD_RELOC_FRV_FUNCDESC_GOTOFFHI +@deffnx {} BFD_RELOC_FRV_FUNCDESC_GOTOFFLO +@deffnx {} BFD_RELOC_FRV_GOTOFF12 +@deffnx {} BFD_RELOC_FRV_GOTOFFHI +@deffnx {} BFD_RELOC_FRV_GOTOFFLO +@deffnx {} BFD_RELOC_FRV_GETTLSOFF +@deffnx {} BFD_RELOC_FRV_TLSDESC_VALUE +@deffnx {} BFD_RELOC_FRV_GOTTLSDESC12 +@deffnx {} BFD_RELOC_FRV_GOTTLSDESCHI +@deffnx {} BFD_RELOC_FRV_GOTTLSDESCLO +@deffnx {} BFD_RELOC_FRV_TLSMOFF12 +@deffnx {} BFD_RELOC_FRV_TLSMOFFHI +@deffnx {} BFD_RELOC_FRV_TLSMOFFLO +@deffnx {} BFD_RELOC_FRV_GOTTLSOFF12 +@deffnx {} BFD_RELOC_FRV_GOTTLSOFFHI +@deffnx {} BFD_RELOC_FRV_GOTTLSOFFLO +@deffnx {} BFD_RELOC_FRV_TLSOFF +@deffnx {} BFD_RELOC_FRV_TLSDESC_RELAX +@deffnx {} BFD_RELOC_FRV_GETTLSOFF_RELAX +@deffnx {} BFD_RELOC_FRV_TLSOFF_RELAX +@deffnx {} BFD_RELOC_FRV_TLSMOFF +Fujitsu Frv Relocations. +@end deffn +@deffn {} BFD_RELOC_MN10300_GOTOFF24 +This is a 24bit GOT-relative reloc for the mn10300. +@end deffn +@deffn {} BFD_RELOC_MN10300_GOT32 +This is a 32bit GOT-relative reloc for the mn10300, offset by two bytes +in the instruction. +@end deffn +@deffn {} BFD_RELOC_MN10300_GOT24 +This is a 24bit GOT-relative reloc for the mn10300, offset by two bytes +in the instruction. +@end deffn +@deffn {} BFD_RELOC_MN10300_GOT16 +This is a 16bit GOT-relative reloc for the mn10300, offset by two bytes +in the instruction. +@end deffn +@deffn {} BFD_RELOC_MN10300_COPY +Copy symbol at runtime. +@end deffn +@deffn {} BFD_RELOC_MN10300_GLOB_DAT +Create GOT entry. +@end deffn +@deffn {} BFD_RELOC_MN10300_JMP_SLOT +Create PLT entry. +@end deffn +@deffn {} BFD_RELOC_MN10300_RELATIVE +Adjust by program base. +@end deffn +@deffn {} BFD_RELOC_386_GOT32 +@deffnx {} BFD_RELOC_386_PLT32 +@deffnx {} BFD_RELOC_386_COPY +@deffnx {} BFD_RELOC_386_GLOB_DAT +@deffnx {} BFD_RELOC_386_JUMP_SLOT +@deffnx {} BFD_RELOC_386_RELATIVE +@deffnx {} BFD_RELOC_386_GOTOFF +@deffnx {} BFD_RELOC_386_GOTPC +@deffnx {} BFD_RELOC_386_TLS_TPOFF +@deffnx {} BFD_RELOC_386_TLS_IE +@deffnx {} BFD_RELOC_386_TLS_GOTIE +@deffnx {} BFD_RELOC_386_TLS_LE +@deffnx {} BFD_RELOC_386_TLS_GD +@deffnx {} BFD_RELOC_386_TLS_LDM +@deffnx {} BFD_RELOC_386_TLS_LDO_32 +@deffnx {} BFD_RELOC_386_TLS_IE_32 +@deffnx {} BFD_RELOC_386_TLS_LE_32 +@deffnx {} BFD_RELOC_386_TLS_DTPMOD32 +@deffnx {} BFD_RELOC_386_TLS_DTPOFF32 +@deffnx {} BFD_RELOC_386_TLS_TPOFF32 +@deffnx {} BFD_RELOC_386_TLS_GOTDESC +@deffnx {} BFD_RELOC_386_TLS_DESC_CALL +@deffnx {} BFD_RELOC_386_TLS_DESC +i386/elf relocations +@end deffn +@deffn {} BFD_RELOC_X86_64_GOT32 +@deffnx {} BFD_RELOC_X86_64_PLT32 +@deffnx {} BFD_RELOC_X86_64_COPY +@deffnx {} BFD_RELOC_X86_64_GLOB_DAT +@deffnx {} BFD_RELOC_X86_64_JUMP_SLOT +@deffnx {} BFD_RELOC_X86_64_RELATIVE +@deffnx {} BFD_RELOC_X86_64_GOTPCREL +@deffnx {} BFD_RELOC_X86_64_32S +@deffnx {} BFD_RELOC_X86_64_DTPMOD64 +@deffnx {} BFD_RELOC_X86_64_DTPOFF64 +@deffnx {} BFD_RELOC_X86_64_TPOFF64 +@deffnx {} BFD_RELOC_X86_64_TLSGD +@deffnx {} BFD_RELOC_X86_64_TLSLD +@deffnx {} BFD_RELOC_X86_64_DTPOFF32 +@deffnx {} BFD_RELOC_X86_64_GOTTPOFF +@deffnx {} BFD_RELOC_X86_64_TPOFF32 +@deffnx {} BFD_RELOC_X86_64_GOTOFF64 +@deffnx {} BFD_RELOC_X86_64_GOTPC32 +@deffnx {} BFD_RELOC_X86_64_GOT64 +@deffnx {} BFD_RELOC_X86_64_GOTPCREL64 +@deffnx {} BFD_RELOC_X86_64_GOTPC64 +@deffnx {} BFD_RELOC_X86_64_GOTPLT64 +@deffnx {} BFD_RELOC_X86_64_PLTOFF64 +@deffnx {} BFD_RELOC_X86_64_GOTPC32_TLSDESC +@deffnx {} BFD_RELOC_X86_64_TLSDESC_CALL +@deffnx {} BFD_RELOC_X86_64_TLSDESC +x86-64/elf relocations +@end deffn +@deffn {} BFD_RELOC_NS32K_IMM_8 +@deffnx {} BFD_RELOC_NS32K_IMM_16 +@deffnx {} BFD_RELOC_NS32K_IMM_32 +@deffnx {} BFD_RELOC_NS32K_IMM_8_PCREL +@deffnx {} BFD_RELOC_NS32K_IMM_16_PCREL +@deffnx {} BFD_RELOC_NS32K_IMM_32_PCREL +@deffnx {} BFD_RELOC_NS32K_DISP_8 +@deffnx {} BFD_RELOC_NS32K_DISP_16 +@deffnx {} BFD_RELOC_NS32K_DISP_32 +@deffnx {} BFD_RELOC_NS32K_DISP_8_PCREL +@deffnx {} BFD_RELOC_NS32K_DISP_16_PCREL +@deffnx {} BFD_RELOC_NS32K_DISP_32_PCREL +ns32k relocations +@end deffn +@deffn {} BFD_RELOC_PDP11_DISP_8_PCREL +@deffnx {} BFD_RELOC_PDP11_DISP_6_PCREL +PDP11 relocations +@end deffn +@deffn {} BFD_RELOC_PJ_CODE_HI16 +@deffnx {} BFD_RELOC_PJ_CODE_LO16 +@deffnx {} BFD_RELOC_PJ_CODE_DIR16 +@deffnx {} BFD_RELOC_PJ_CODE_DIR32 +@deffnx {} BFD_RELOC_PJ_CODE_REL16 +@deffnx {} BFD_RELOC_PJ_CODE_REL32 +Picojava relocs. Not all of these appear in object files. +@end deffn +@deffn {} BFD_RELOC_PPC_B26 +@deffnx {} BFD_RELOC_PPC_BA26 +@deffnx {} BFD_RELOC_PPC_TOC16 +@deffnx {} BFD_RELOC_PPC_B16 +@deffnx {} BFD_RELOC_PPC_B16_BRTAKEN +@deffnx {} BFD_RELOC_PPC_B16_BRNTAKEN +@deffnx {} BFD_RELOC_PPC_BA16 +@deffnx {} BFD_RELOC_PPC_BA16_BRTAKEN +@deffnx {} BFD_RELOC_PPC_BA16_BRNTAKEN +@deffnx {} BFD_RELOC_PPC_COPY +@deffnx {} BFD_RELOC_PPC_GLOB_DAT +@deffnx {} BFD_RELOC_PPC_JMP_SLOT +@deffnx {} BFD_RELOC_PPC_RELATIVE +@deffnx {} BFD_RELOC_PPC_LOCAL24PC +@deffnx {} BFD_RELOC_PPC_EMB_NADDR32 +@deffnx {} BFD_RELOC_PPC_EMB_NADDR16 +@deffnx {} BFD_RELOC_PPC_EMB_NADDR16_LO +@deffnx {} BFD_RELOC_PPC_EMB_NADDR16_HI +@deffnx {} BFD_RELOC_PPC_EMB_NADDR16_HA +@deffnx {} BFD_RELOC_PPC_EMB_SDAI16 +@deffnx {} BFD_RELOC_PPC_EMB_SDA2I16 +@deffnx {} BFD_RELOC_PPC_EMB_SDA2REL +@deffnx {} BFD_RELOC_PPC_EMB_SDA21 +@deffnx {} BFD_RELOC_PPC_EMB_MRKREF +@deffnx {} BFD_RELOC_PPC_EMB_RELSEC16 +@deffnx {} BFD_RELOC_PPC_EMB_RELST_LO +@deffnx {} BFD_RELOC_PPC_EMB_RELST_HI +@deffnx {} BFD_RELOC_PPC_EMB_RELST_HA +@deffnx {} BFD_RELOC_PPC_EMB_BIT_FLD +@deffnx {} BFD_RELOC_PPC_EMB_RELSDA +@deffnx {} BFD_RELOC_PPC64_HIGHER +@deffnx {} BFD_RELOC_PPC64_HIGHER_S +@deffnx {} BFD_RELOC_PPC64_HIGHEST +@deffnx {} BFD_RELOC_PPC64_HIGHEST_S +@deffnx {} BFD_RELOC_PPC64_TOC16_LO +@deffnx {} BFD_RELOC_PPC64_TOC16_HI +@deffnx {} BFD_RELOC_PPC64_TOC16_HA +@deffnx {} BFD_RELOC_PPC64_TOC +@deffnx {} BFD_RELOC_PPC64_PLTGOT16 +@deffnx {} BFD_RELOC_PPC64_PLTGOT16_LO +@deffnx {} BFD_RELOC_PPC64_PLTGOT16_HI +@deffnx {} BFD_RELOC_PPC64_PLTGOT16_HA +@deffnx {} BFD_RELOC_PPC64_ADDR16_DS +@deffnx {} BFD_RELOC_PPC64_ADDR16_LO_DS +@deffnx {} BFD_RELOC_PPC64_GOT16_DS +@deffnx {} BFD_RELOC_PPC64_GOT16_LO_DS +@deffnx {} BFD_RELOC_PPC64_PLT16_LO_DS +@deffnx {} BFD_RELOC_PPC64_SECTOFF_DS +@deffnx {} BFD_RELOC_PPC64_SECTOFF_LO_DS +@deffnx {} BFD_RELOC_PPC64_TOC16_DS +@deffnx {} BFD_RELOC_PPC64_TOC16_LO_DS +@deffnx {} BFD_RELOC_PPC64_PLTGOT16_DS +@deffnx {} BFD_RELOC_PPC64_PLTGOT16_LO_DS +Power(rs6000) and PowerPC relocations. +@end deffn +@deffn {} BFD_RELOC_PPC_TLS +@deffnx {} BFD_RELOC_PPC_DTPMOD +@deffnx {} BFD_RELOC_PPC_TPREL16 +@deffnx {} BFD_RELOC_PPC_TPREL16_LO +@deffnx {} BFD_RELOC_PPC_TPREL16_HI +@deffnx {} BFD_RELOC_PPC_TPREL16_HA +@deffnx {} BFD_RELOC_PPC_TPREL +@deffnx {} BFD_RELOC_PPC_DTPREL16 +@deffnx {} BFD_RELOC_PPC_DTPREL16_LO +@deffnx {} BFD_RELOC_PPC_DTPREL16_HI +@deffnx {} BFD_RELOC_PPC_DTPREL16_HA +@deffnx {} BFD_RELOC_PPC_DTPREL +@deffnx {} BFD_RELOC_PPC_GOT_TLSGD16 +@deffnx {} BFD_RELOC_PPC_GOT_TLSGD16_LO +@deffnx {} BFD_RELOC_PPC_GOT_TLSGD16_HI +@deffnx {} BFD_RELOC_PPC_GOT_TLSGD16_HA +@deffnx {} BFD_RELOC_PPC_GOT_TLSLD16 +@deffnx {} BFD_RELOC_PPC_GOT_TLSLD16_LO +@deffnx {} BFD_RELOC_PPC_GOT_TLSLD16_HI +@deffnx {} BFD_RELOC_PPC_GOT_TLSLD16_HA +@deffnx {} BFD_RELOC_PPC_GOT_TPREL16 +@deffnx {} BFD_RELOC_PPC_GOT_TPREL16_LO +@deffnx {} BFD_RELOC_PPC_GOT_TPREL16_HI +@deffnx {} BFD_RELOC_PPC_GOT_TPREL16_HA +@deffnx {} BFD_RELOC_PPC_GOT_DTPREL16 +@deffnx {} BFD_RELOC_PPC_GOT_DTPREL16_LO +@deffnx {} BFD_RELOC_PPC_GOT_DTPREL16_HI +@deffnx {} BFD_RELOC_PPC_GOT_DTPREL16_HA +@deffnx {} BFD_RELOC_PPC64_TPREL16_DS +@deffnx {} BFD_RELOC_PPC64_TPREL16_LO_DS +@deffnx {} BFD_RELOC_PPC64_TPREL16_HIGHER +@deffnx {} BFD_RELOC_PPC64_TPREL16_HIGHERA +@deffnx {} BFD_RELOC_PPC64_TPREL16_HIGHEST +@deffnx {} BFD_RELOC_PPC64_TPREL16_HIGHESTA +@deffnx {} BFD_RELOC_PPC64_DTPREL16_DS +@deffnx {} BFD_RELOC_PPC64_DTPREL16_LO_DS +@deffnx {} BFD_RELOC_PPC64_DTPREL16_HIGHER +@deffnx {} BFD_RELOC_PPC64_DTPREL16_HIGHERA +@deffnx {} BFD_RELOC_PPC64_DTPREL16_HIGHEST +@deffnx {} BFD_RELOC_PPC64_DTPREL16_HIGHESTA +PowerPC and PowerPC64 thread-local storage relocations. +@end deffn +@deffn {} BFD_RELOC_I370_D12 +IBM 370/390 relocations +@end deffn +@deffn {} BFD_RELOC_CTOR +The type of reloc used to build a constructor 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. +@end deffn +@deffn {} BFD_RELOC_ARM_PCREL_BRANCH +ARM 26 bit pc-relative branch. The lowest two bits must be zero and are +not stored in the instruction. +@end deffn +@deffn {} BFD_RELOC_ARM_PCREL_BLX +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. +@end deffn +@deffn {} BFD_RELOC_THUMB_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. +@end deffn +@deffn {} BFD_RELOC_ARM_PCREL_CALL +ARM 26-bit pc-relative branch for an unconditional BL or BLX instruction. +@end deffn +@deffn {} BFD_RELOC_ARM_PCREL_JUMP +ARM 26-bit pc-relative branch for B or conditional BL instruction. +@end deffn +@deffn {} BFD_RELOC_THUMB_PCREL_BRANCH7 +@deffnx {} BFD_RELOC_THUMB_PCREL_BRANCH9 +@deffnx {} BFD_RELOC_THUMB_PCREL_BRANCH12 +@deffnx {} BFD_RELOC_THUMB_PCREL_BRANCH20 +@deffnx {} BFD_RELOC_THUMB_PCREL_BRANCH23 +@deffnx {} BFD_RELOC_THUMB_PCREL_BRANCH25 +Thumb 7-, 9-, 12-, 20-, 23-, and 25-bit pc-relative branches. +The lowest bit must be zero and is not stored in the instruction. +Note that the corresponding ELF R_ARM_THM_JUMPnn constant has an +"nn" one smaller in all cases. Note further that BRANCH23 +corresponds to R_ARM_THM_CALL. +@end deffn +@deffn {} BFD_RELOC_ARM_OFFSET_IMM +12-bit immediate offset, used in ARM-format ldr and str instructions. +@end deffn +@deffn {} BFD_RELOC_ARM_THUMB_OFFSET +5-bit immediate offset, used in Thumb-format ldr and str instructions. +@end deffn +@deffn {} BFD_RELOC_ARM_TARGET1 +Pc-relative or absolute relocation depending on target. Used for +entries in .init_array sections. +@end deffn +@deffn {} BFD_RELOC_ARM_ROSEGREL32 +Read-only segment base relative address. +@end deffn +@deffn {} BFD_RELOC_ARM_SBREL32 +Data segment base relative address. +@end deffn +@deffn {} BFD_RELOC_ARM_TARGET2 +This reloc is used for references to RTTI data from exception handling +tables. The actual definition depends on the target. It may be a +pc-relative or some form of GOT-indirect relocation. +@end deffn +@deffn {} BFD_RELOC_ARM_PREL31 +31-bit PC relative address. +@end deffn +@deffn {} BFD_RELOC_ARM_JUMP_SLOT +@deffnx {} BFD_RELOC_ARM_GLOB_DAT +@deffnx {} BFD_RELOC_ARM_GOT32 +@deffnx {} BFD_RELOC_ARM_PLT32 +@deffnx {} BFD_RELOC_ARM_RELATIVE +@deffnx {} BFD_RELOC_ARM_GOTOFF +@deffnx {} BFD_RELOC_ARM_GOTPC +Relocations for setting up GOTs and PLTs for shared libraries. +@end deffn +@deffn {} BFD_RELOC_ARM_TLS_GD32 +@deffnx {} BFD_RELOC_ARM_TLS_LDO32 +@deffnx {} BFD_RELOC_ARM_TLS_LDM32 +@deffnx {} BFD_RELOC_ARM_TLS_DTPOFF32 +@deffnx {} BFD_RELOC_ARM_TLS_DTPMOD32 +@deffnx {} BFD_RELOC_ARM_TLS_TPOFF32 +@deffnx {} BFD_RELOC_ARM_TLS_IE32 +@deffnx {} BFD_RELOC_ARM_TLS_LE32 +ARM thread-local storage relocations. +@end deffn +@deffn {} BFD_RELOC_ARM_IMMEDIATE +@deffnx {} BFD_RELOC_ARM_ADRL_IMMEDIATE +@deffnx {} BFD_RELOC_ARM_T32_IMMEDIATE +@deffnx {} BFD_RELOC_ARM_T32_IMM12 +@deffnx {} BFD_RELOC_ARM_T32_ADD_PC12 +@deffnx {} BFD_RELOC_ARM_SHIFT_IMM +@deffnx {} BFD_RELOC_ARM_SMC +@deffnx {} BFD_RELOC_ARM_SWI +@deffnx {} BFD_RELOC_ARM_MULTI +@deffnx {} BFD_RELOC_ARM_CP_OFF_IMM +@deffnx {} BFD_RELOC_ARM_CP_OFF_IMM_S2 +@deffnx {} BFD_RELOC_ARM_T32_CP_OFF_IMM +@deffnx {} BFD_RELOC_ARM_T32_CP_OFF_IMM_S2 +@deffnx {} BFD_RELOC_ARM_ADR_IMM +@deffnx {} BFD_RELOC_ARM_LDR_IMM +@deffnx {} BFD_RELOC_ARM_LITERAL +@deffnx {} BFD_RELOC_ARM_IN_POOL +@deffnx {} BFD_RELOC_ARM_OFFSET_IMM8 +@deffnx {} BFD_RELOC_ARM_T32_OFFSET_U8 +@deffnx {} BFD_RELOC_ARM_T32_OFFSET_IMM +@deffnx {} BFD_RELOC_ARM_HWLITERAL +@deffnx {} BFD_RELOC_ARM_THUMB_ADD +@deffnx {} BFD_RELOC_ARM_THUMB_IMM +@deffnx {} BFD_RELOC_ARM_THUMB_SHIFT +These relocs are only used within the ARM assembler. They are not +(at present) written to any object files. +@end deffn +@deffn {} BFD_RELOC_SH_PCDISP8BY2 +@deffnx {} BFD_RELOC_SH_PCDISP12BY2 +@deffnx {} BFD_RELOC_SH_IMM3 +@deffnx {} BFD_RELOC_SH_IMM3U +@deffnx {} BFD_RELOC_SH_DISP12 +@deffnx {} BFD_RELOC_SH_DISP12BY2 +@deffnx {} BFD_RELOC_SH_DISP12BY4 +@deffnx {} BFD_RELOC_SH_DISP12BY8 +@deffnx {} BFD_RELOC_SH_DISP20 +@deffnx {} BFD_RELOC_SH_DISP20BY8 +@deffnx {} BFD_RELOC_SH_IMM4 +@deffnx {} BFD_RELOC_SH_IMM4BY2 +@deffnx {} BFD_RELOC_SH_IMM4BY4 +@deffnx {} BFD_RELOC_SH_IMM8 +@deffnx {} BFD_RELOC_SH_IMM8BY2 +@deffnx {} BFD_RELOC_SH_IMM8BY4 +@deffnx {} BFD_RELOC_SH_PCRELIMM8BY2 +@deffnx {} BFD_RELOC_SH_PCRELIMM8BY4 +@deffnx {} BFD_RELOC_SH_SWITCH16 +@deffnx {} BFD_RELOC_SH_SWITCH32 +@deffnx {} BFD_RELOC_SH_USES +@deffnx {} BFD_RELOC_SH_COUNT +@deffnx {} BFD_RELOC_SH_ALIGN +@deffnx {} BFD_RELOC_SH_CODE +@deffnx {} BFD_RELOC_SH_DATA +@deffnx {} BFD_RELOC_SH_LABEL +@deffnx {} BFD_RELOC_SH_LOOP_START +@deffnx {} BFD_RELOC_SH_LOOP_END +@deffnx {} BFD_RELOC_SH_COPY +@deffnx {} BFD_RELOC_SH_GLOB_DAT +@deffnx {} BFD_RELOC_SH_JMP_SLOT +@deffnx {} BFD_RELOC_SH_RELATIVE +@deffnx {} BFD_RELOC_SH_GOTPC +@deffnx {} BFD_RELOC_SH_GOT_LOW16 +@deffnx {} BFD_RELOC_SH_GOT_MEDLOW16 +@deffnx {} BFD_RELOC_SH_GOT_MEDHI16 +@deffnx {} BFD_RELOC_SH_GOT_HI16 +@deffnx {} BFD_RELOC_SH_GOTPLT_LOW16 +@deffnx {} BFD_RELOC_SH_GOTPLT_MEDLOW16 +@deffnx {} BFD_RELOC_SH_GOTPLT_MEDHI16 +@deffnx {} BFD_RELOC_SH_GOTPLT_HI16 +@deffnx {} BFD_RELOC_SH_PLT_LOW16 +@deffnx {} BFD_RELOC_SH_PLT_MEDLOW16 +@deffnx {} BFD_RELOC_SH_PLT_MEDHI16 +@deffnx {} BFD_RELOC_SH_PLT_HI16 +@deffnx {} BFD_RELOC_SH_GOTOFF_LOW16 +@deffnx {} BFD_RELOC_SH_GOTOFF_MEDLOW16 +@deffnx {} BFD_RELOC_SH_GOTOFF_MEDHI16 +@deffnx {} BFD_RELOC_SH_GOTOFF_HI16 +@deffnx {} BFD_RELOC_SH_GOTPC_LOW16 +@deffnx {} BFD_RELOC_SH_GOTPC_MEDLOW16 +@deffnx {} BFD_RELOC_SH_GOTPC_MEDHI16 +@deffnx {} BFD_RELOC_SH_GOTPC_HI16 +@deffnx {} BFD_RELOC_SH_COPY64 +@deffnx {} BFD_RELOC_SH_GLOB_DAT64 +@deffnx {} BFD_RELOC_SH_JMP_SLOT64 +@deffnx {} BFD_RELOC_SH_RELATIVE64 +@deffnx {} BFD_RELOC_SH_GOT10BY4 +@deffnx {} BFD_RELOC_SH_GOT10BY8 +@deffnx {} BFD_RELOC_SH_GOTPLT10BY4 +@deffnx {} BFD_RELOC_SH_GOTPLT10BY8 +@deffnx {} BFD_RELOC_SH_GOTPLT32 +@deffnx {} BFD_RELOC_SH_SHMEDIA_CODE +@deffnx {} BFD_RELOC_SH_IMMU5 +@deffnx {} BFD_RELOC_SH_IMMS6 +@deffnx {} BFD_RELOC_SH_IMMS6BY32 +@deffnx {} BFD_RELOC_SH_IMMU6 +@deffnx {} BFD_RELOC_SH_IMMS10 +@deffnx {} BFD_RELOC_SH_IMMS10BY2 +@deffnx {} BFD_RELOC_SH_IMMS10BY4 +@deffnx {} BFD_RELOC_SH_IMMS10BY8 +@deffnx {} BFD_RELOC_SH_IMMS16 +@deffnx {} BFD_RELOC_SH_IMMU16 +@deffnx {} BFD_RELOC_SH_IMM_LOW16 +@deffnx {} BFD_RELOC_SH_IMM_LOW16_PCREL +@deffnx {} BFD_RELOC_SH_IMM_MEDLOW16 +@deffnx {} BFD_RELOC_SH_IMM_MEDLOW16_PCREL +@deffnx {} BFD_RELOC_SH_IMM_MEDHI16 +@deffnx {} BFD_RELOC_SH_IMM_MEDHI16_PCREL +@deffnx {} BFD_RELOC_SH_IMM_HI16 +@deffnx {} BFD_RELOC_SH_IMM_HI16_PCREL +@deffnx {} BFD_RELOC_SH_PT_16 +@deffnx {} BFD_RELOC_SH_TLS_GD_32 +@deffnx {} BFD_RELOC_SH_TLS_LD_32 +@deffnx {} BFD_RELOC_SH_TLS_LDO_32 +@deffnx {} BFD_RELOC_SH_TLS_IE_32 +@deffnx {} BFD_RELOC_SH_TLS_LE_32 +@deffnx {} BFD_RELOC_SH_TLS_DTPMOD32 +@deffnx {} BFD_RELOC_SH_TLS_DTPOFF32 +@deffnx {} BFD_RELOC_SH_TLS_TPOFF32 +Renesas / SuperH SH relocs. Not all of these appear in object files. +@end deffn +@deffn {} BFD_RELOC_ARC_B22_PCREL +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. +@end deffn +@deffn {} BFD_RELOC_ARC_B26 +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. +@end deffn +@deffn {} BFD_RELOC_BFIN_16_IMM +ADI Blackfin 16 bit immediate absolute reloc. +@end deffn +@deffn {} BFD_RELOC_BFIN_16_HIGH +ADI Blackfin 16 bit immediate absolute reloc higher 16 bits. +@end deffn +@deffn {} BFD_RELOC_BFIN_4_PCREL +ADI Blackfin 'a' part of LSETUP. +@end deffn +@deffn {} BFD_RELOC_BFIN_5_PCREL +ADI Blackfin. +@end deffn +@deffn {} BFD_RELOC_BFIN_16_LOW +ADI Blackfin 16 bit immediate absolute reloc lower 16 bits. +@end deffn +@deffn {} BFD_RELOC_BFIN_10_PCREL +ADI Blackfin. +@end deffn +@deffn {} BFD_RELOC_BFIN_11_PCREL +ADI Blackfin 'b' part of LSETUP. +@end deffn +@deffn {} BFD_RELOC_BFIN_12_PCREL_JUMP +ADI Blackfin. +@end deffn +@deffn {} BFD_RELOC_BFIN_12_PCREL_JUMP_S +ADI Blackfin Short jump, pcrel. +@end deffn +@deffn {} BFD_RELOC_BFIN_24_PCREL_CALL_X +ADI Blackfin Call.x not implemented. +@end deffn +@deffn {} BFD_RELOC_BFIN_24_PCREL_JUMP_L +ADI Blackfin Long Jump pcrel. +@end deffn +@deffn {} BFD_RELOC_BFIN_GOT17M4 +@deffnx {} BFD_RELOC_BFIN_GOTHI +@deffnx {} BFD_RELOC_BFIN_GOTLO +@deffnx {} BFD_RELOC_BFIN_FUNCDESC +@deffnx {} BFD_RELOC_BFIN_FUNCDESC_GOT17M4 +@deffnx {} BFD_RELOC_BFIN_FUNCDESC_GOTHI +@deffnx {} BFD_RELOC_BFIN_FUNCDESC_GOTLO +@deffnx {} BFD_RELOC_BFIN_FUNCDESC_VALUE +@deffnx {} BFD_RELOC_BFIN_FUNCDESC_GOTOFF17M4 +@deffnx {} BFD_RELOC_BFIN_FUNCDESC_GOTOFFHI +@deffnx {} BFD_RELOC_BFIN_FUNCDESC_GOTOFFLO +@deffnx {} BFD_RELOC_BFIN_GOTOFF17M4 +@deffnx {} BFD_RELOC_BFIN_GOTOFFHI +@deffnx {} BFD_RELOC_BFIN_GOTOFFLO +ADI Blackfin FD-PIC relocations. +@end deffn +@deffn {} BFD_RELOC_BFIN_GOT +ADI Blackfin GOT relocation. +@end deffn +@deffn {} BFD_RELOC_BFIN_PLTPC +ADI Blackfin PLTPC relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_PUSH +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_CONST +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_ADD +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_SUB +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_MULT +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_DIV +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_MOD +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_LSHIFT +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_RSHIFT +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_AND +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_OR +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_XOR +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_LAND +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_LOR +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_LEN +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_NEG +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_COMP +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_PAGE +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_HWPAGE +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_ARELOC_BFIN_ADDR +ADI Blackfin arithmetic relocation. +@end deffn +@deffn {} BFD_RELOC_D10V_10_PCREL_R +Mitsubishi D10V relocs. +This is a 10-bit reloc with the right 2 bits +assumed to be 0. +@end deffn +@deffn {} BFD_RELOC_D10V_10_PCREL_L +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. +@end deffn +@deffn {} BFD_RELOC_D10V_18 +This is an 18-bit reloc with the right 2 bits +assumed to be 0. +@end deffn +@deffn {} BFD_RELOC_D10V_18_PCREL +This is an 18-bit reloc with the right 2 bits +assumed to be 0. +@end deffn +@deffn {} BFD_RELOC_D30V_6 +Mitsubishi D30V relocs. +This is a 6-bit absolute reloc. +@end deffn +@deffn {} BFD_RELOC_D30V_9_PCREL +This is a 6-bit pc-relative reloc with +the right 3 bits assumed to be 0. +@end deffn +@deffn {} BFD_RELOC_D30V_9_PCREL_R +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. +@end deffn +@deffn {} BFD_RELOC_D30V_15 +This is a 12-bit absolute reloc with the +right 3 bitsassumed to be 0. +@end deffn +@deffn {} BFD_RELOC_D30V_15_PCREL +This is a 12-bit pc-relative reloc with +the right 3 bits assumed to be 0. +@end deffn +@deffn {} BFD_RELOC_D30V_15_PCREL_R +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. +@end deffn +@deffn {} BFD_RELOC_D30V_21 +This is an 18-bit absolute reloc with +the right 3 bits assumed to be 0. +@end deffn +@deffn {} BFD_RELOC_D30V_21_PCREL +This is an 18-bit pc-relative reloc with +the right 3 bits assumed to be 0. +@end deffn +@deffn {} BFD_RELOC_D30V_21_PCREL_R +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. +@end deffn +@deffn {} BFD_RELOC_D30V_32 +This is a 32-bit absolute reloc. +@end deffn +@deffn {} BFD_RELOC_D30V_32_PCREL +This is a 32-bit pc-relative reloc. +@end deffn +@deffn {} BFD_RELOC_DLX_HI16_S +DLX relocs +@end deffn +@deffn {} BFD_RELOC_DLX_LO16 +DLX relocs +@end deffn +@deffn {} BFD_RELOC_DLX_JMP26 +DLX relocs +@end deffn +@deffn {} BFD_RELOC_M32C_HI8 +@deffnx {} BFD_RELOC_M32C_RL_JUMP +@deffnx {} BFD_RELOC_M32C_RL_1ADDR +@deffnx {} BFD_RELOC_M32C_RL_2ADDR +Renesas M16C/M32C Relocations. +@end deffn +@deffn {} BFD_RELOC_M32R_24 +Renesas M32R (formerly Mitsubishi M32R) relocs. +This is a 24 bit absolute address. +@end deffn +@deffn {} BFD_RELOC_M32R_10_PCREL +This is a 10-bit pc-relative reloc with the right 2 bits assumed to be 0. +@end deffn +@deffn {} BFD_RELOC_M32R_18_PCREL +This is an 18-bit reloc with the right 2 bits assumed to be 0. +@end deffn +@deffn {} BFD_RELOC_M32R_26_PCREL +This is a 26-bit reloc with the right 2 bits assumed to be 0. +@end deffn +@deffn {} 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 unsigned. +@end deffn +@deffn {} BFD_RELOC_M32R_HI16_SLO +This is a 16-bit reloc containing the high 16 bits of an address +used when the lower 16 bits are treated as signed. +@end deffn +@deffn {} BFD_RELOC_M32R_LO16 +This is a 16-bit reloc containing the lower 16 bits of an address. +@end deffn +@deffn {} BFD_RELOC_M32R_SDA16 +This is a 16-bit reloc containing the small data area offset for use in +add3, load, and store instructions. +@end deffn +@deffn {} BFD_RELOC_M32R_GOT24 +@deffnx {} BFD_RELOC_M32R_26_PLTREL +@deffnx {} BFD_RELOC_M32R_COPY +@deffnx {} BFD_RELOC_M32R_GLOB_DAT +@deffnx {} BFD_RELOC_M32R_JMP_SLOT +@deffnx {} BFD_RELOC_M32R_RELATIVE +@deffnx {} BFD_RELOC_M32R_GOTOFF +@deffnx {} BFD_RELOC_M32R_GOTOFF_HI_ULO +@deffnx {} BFD_RELOC_M32R_GOTOFF_HI_SLO +@deffnx {} BFD_RELOC_M32R_GOTOFF_LO +@deffnx {} BFD_RELOC_M32R_GOTPC24 +@deffnx {} BFD_RELOC_M32R_GOT16_HI_ULO +@deffnx {} BFD_RELOC_M32R_GOT16_HI_SLO +@deffnx {} BFD_RELOC_M32R_GOT16_LO +@deffnx {} BFD_RELOC_M32R_GOTPC_HI_ULO +@deffnx {} BFD_RELOC_M32R_GOTPC_HI_SLO +@deffnx {} BFD_RELOC_M32R_GOTPC_LO +For PIC. +@end deffn +@deffn {} BFD_RELOC_V850_9_PCREL +This is a 9-bit reloc +@end deffn +@deffn {} BFD_RELOC_V850_22_PCREL +This is a 22-bit reloc +@end deffn +@deffn {} BFD_RELOC_V850_SDA_16_16_OFFSET +This is a 16 bit offset from the short data area pointer. +@end deffn +@deffn {} BFD_RELOC_V850_SDA_15_16_OFFSET +This is a 16 bit offset (of which only 15 bits are used) from the +short data area pointer. +@end deffn +@deffn {} BFD_RELOC_V850_ZDA_16_16_OFFSET +This is a 16 bit offset from the zero data area pointer. +@end deffn +@deffn {} BFD_RELOC_V850_ZDA_15_16_OFFSET +This is a 16 bit offset (of which only 15 bits are used) from the +zero data area pointer. +@end deffn +@deffn {} BFD_RELOC_V850_TDA_6_8_OFFSET +This is an 8 bit offset (of which only 6 bits are used) from the +tiny data area pointer. +@end deffn +@deffn {} BFD_RELOC_V850_TDA_7_8_OFFSET +This is an 8bit offset (of which only 7 bits are used) from the tiny +data area pointer. +@end deffn +@deffn {} BFD_RELOC_V850_TDA_7_7_OFFSET +This is a 7 bit offset from the tiny data area pointer. +@end deffn +@deffn {} BFD_RELOC_V850_TDA_16_16_OFFSET +This is a 16 bit offset from the tiny data area pointer. +@end deffn +@deffn {} BFD_RELOC_V850_TDA_4_5_OFFSET +This is a 5 bit offset (of which only 4 bits are used) from the tiny +data area pointer. +@end deffn +@deffn {} BFD_RELOC_V850_TDA_4_4_OFFSET +This is a 4 bit offset from the tiny data area pointer. +@end deffn +@deffn {} BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET +This is a 16 bit offset from the short data area pointer, with the +bits placed non-contiguously in the instruction. +@end deffn +@deffn {} BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET +This is a 16 bit offset from the zero data area pointer, with the +bits placed non-contiguously in the instruction. +@end deffn +@deffn {} BFD_RELOC_V850_CALLT_6_7_OFFSET +This is a 6 bit offset from the call table base pointer. +@end deffn +@deffn {} BFD_RELOC_V850_CALLT_16_16_OFFSET +This is a 16 bit offset from the call table base pointer. +@end deffn +@deffn {} BFD_RELOC_V850_LONGCALL +Used for relaxing indirect function calls. +@end deffn +@deffn {} BFD_RELOC_V850_LONGJUMP +Used for relaxing indirect jumps. +@end deffn +@deffn {} BFD_RELOC_V850_ALIGN +Used to maintain alignment whilst relaxing. +@end deffn +@deffn {} BFD_RELOC_V850_LO16_SPLIT_OFFSET +This is a variation of BFD_RELOC_LO16 that can be used in v850e ld.bu +instructions. +@end deffn +@deffn {} BFD_RELOC_MN10300_32_PCREL +This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the +instruction. +@end deffn +@deffn {} BFD_RELOC_MN10300_16_PCREL +This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the +instruction. +@end deffn +@deffn {} BFD_RELOC_TIC30_LDP +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. +@end deffn +@deffn {} BFD_RELOC_TIC54X_PARTLS7 +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. +@end deffn +@deffn {} BFD_RELOC_TIC54X_PARTMS9 +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. +@end deffn +@deffn {} BFD_RELOC_TIC54X_23 +This is an extended address 23-bit reloc for the tms320c54x. +@end deffn +@deffn {} BFD_RELOC_TIC54X_16_OF_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. +@end deffn +@deffn {} BFD_RELOC_TIC54X_MS7_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. +@end deffn +@deffn {} BFD_RELOC_FR30_48 +This is a 48 bit reloc for the FR30 that stores 32 bits. +@end deffn +@deffn {} BFD_RELOC_FR30_20 +This is a 32 bit reloc for the FR30 that stores 20 bits split up into +two sections. +@end deffn +@deffn {} BFD_RELOC_FR30_6_IN_4 +This is a 16 bit reloc for the FR30 that stores a 6 bit word offset in +4 bits. +@end deffn +@deffn {} BFD_RELOC_FR30_8_IN_8 +This is a 16 bit reloc for the FR30 that stores an 8 bit byte offset +into 8 bits. +@end deffn +@deffn {} BFD_RELOC_FR30_9_IN_8 +This is a 16 bit reloc for the FR30 that stores a 9 bit short offset +into 8 bits. +@end deffn +@deffn {} BFD_RELOC_FR30_10_IN_8 +This is a 16 bit reloc for the FR30 that stores a 10 bit word offset +into 8 bits. +@end deffn +@deffn {} BFD_RELOC_FR30_9_PCREL +This is a 16 bit reloc for the FR30 that stores a 9 bit pc relative +short offset into 8 bits. +@end deffn +@deffn {} BFD_RELOC_FR30_12_PCREL +This is a 16 bit reloc for the FR30 that stores a 12 bit pc relative +short offset into 11 bits. +@end deffn +@deffn {} BFD_RELOC_MCORE_PCREL_IMM8BY4 +@deffnx {} BFD_RELOC_MCORE_PCREL_IMM11BY2 +@deffnx {} BFD_RELOC_MCORE_PCREL_IMM4BY2 +@deffnx {} BFD_RELOC_MCORE_PCREL_32 +@deffnx {} BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2 +@deffnx {} BFD_RELOC_MCORE_RVA +Motorola Mcore relocations. +@end deffn +@deffn {} BFD_RELOC_MMIX_GETA +@deffnx {} BFD_RELOC_MMIX_GETA_1 +@deffnx {} BFD_RELOC_MMIX_GETA_2 +@deffnx {} BFD_RELOC_MMIX_GETA_3 +These are relocations for the GETA instruction. +@end deffn +@deffn {} BFD_RELOC_MMIX_CBRANCH +@deffnx {} BFD_RELOC_MMIX_CBRANCH_J +@deffnx {} BFD_RELOC_MMIX_CBRANCH_1 +@deffnx {} BFD_RELOC_MMIX_CBRANCH_2 +@deffnx {} BFD_RELOC_MMIX_CBRANCH_3 +These are relocations for a conditional branch instruction. +@end deffn +@deffn {} BFD_RELOC_MMIX_PUSHJ +@deffnx {} BFD_RELOC_MMIX_PUSHJ_1 +@deffnx {} BFD_RELOC_MMIX_PUSHJ_2 +@deffnx {} BFD_RELOC_MMIX_PUSHJ_3 +@deffnx {} BFD_RELOC_MMIX_PUSHJ_STUBBABLE +These are relocations for the PUSHJ instruction. +@end deffn +@deffn {} BFD_RELOC_MMIX_JMP +@deffnx {} BFD_RELOC_MMIX_JMP_1 +@deffnx {} BFD_RELOC_MMIX_JMP_2 +@deffnx {} BFD_RELOC_MMIX_JMP_3 +These are relocations for the JMP instruction. +@end deffn +@deffn {} BFD_RELOC_MMIX_ADDR19 +This is a relocation for a relative address as in a GETA instruction or +a branch. +@end deffn +@deffn {} BFD_RELOC_MMIX_ADDR27 +This is a relocation for a relative address as in a JMP instruction. +@end deffn +@deffn {} BFD_RELOC_MMIX_REG_OR_BYTE +This is a relocation for an instruction field that may be a general +register or a value 0..255. +@end deffn +@deffn {} BFD_RELOC_MMIX_REG +This is a relocation for an instruction field that may be a general +register. +@end deffn +@deffn {} BFD_RELOC_MMIX_BASE_PLUS_OFFSET +This is a relocation for two instruction fields holding a register and +an offset, the equivalent of the relocation. +@end deffn +@deffn {} BFD_RELOC_MMIX_LOCAL +This relocation is an assertion that the expression is not allocated as +a global register. It does not modify contents. +@end deffn +@deffn {} BFD_RELOC_AVR_7_PCREL +This is a 16 bit reloc for the AVR that stores 8 bit pc relative +short offset into 7 bits. +@end deffn +@deffn {} BFD_RELOC_AVR_13_PCREL +This is a 16 bit reloc for the AVR that stores 13 bit pc relative +short offset into 12 bits. +@end deffn +@deffn {} BFD_RELOC_AVR_16_PM +This is a 16 bit reloc for the AVR that stores 17 bit value (usually +program memory address) into 16 bits. +@end deffn +@deffn {} BFD_RELOC_AVR_LO8_LDI +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. +@end deffn +@deffn {} BFD_RELOC_AVR_HI8_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. +@end deffn +@deffn {} BFD_RELOC_AVR_HH8_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. +@end deffn +@deffn {} BFD_RELOC_AVR_MS8_LDI +This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit +of 32 bit value) into 8 bit immediate value of LDI insn. +@end deffn +@deffn {} BFD_RELOC_AVR_LO8_LDI_NEG +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. +@end deffn +@deffn {} BFD_RELOC_AVR_HI8_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. +@end deffn +@deffn {} BFD_RELOC_AVR_HH8_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. +@end deffn +@deffn {} BFD_RELOC_AVR_MS8_LDI_NEG +This is a 16 bit reloc for the AVR that stores negated 8 bit value (msb +of 32 bit value) into 8 bit immediate value of LDI insn. +@end deffn +@deffn {} BFD_RELOC_AVR_LO8_LDI_PM +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. +@end deffn +@deffn {} BFD_RELOC_AVR_HI8_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. +@end deffn +@deffn {} BFD_RELOC_AVR_HH8_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. +@end deffn +@deffn {} BFD_RELOC_AVR_LO8_LDI_PM_NEG +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. +@end deffn +@deffn {} BFD_RELOC_AVR_HI8_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. +@end deffn +@deffn {} BFD_RELOC_AVR_HH8_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. +@end deffn +@deffn {} BFD_RELOC_AVR_CALL +This is a 32 bit reloc for the AVR that stores 23 bit value +into 22 bits. +@end deffn +@deffn {} BFD_RELOC_AVR_LDI +This is a 16 bit reloc for the AVR that stores all needed bits +for absolute addressing with ldi with overflow check to linktime +@end deffn +@deffn {} BFD_RELOC_AVR_6 +This is a 6 bit reloc for the AVR that stores offset for ldd/std +instructions +@end deffn +@deffn {} BFD_RELOC_AVR_6_ADIW +This is a 6 bit reloc for the AVR that stores offset for adiw/sbiw +instructions +@end deffn +@deffn {} BFD_RELOC_390_12 +Direct 12 bit. +@end deffn +@deffn {} BFD_RELOC_390_GOT12 +12 bit GOT offset. +@end deffn +@deffn {} BFD_RELOC_390_PLT32 +32 bit PC relative PLT address. +@end deffn +@deffn {} BFD_RELOC_390_COPY +Copy symbol at runtime. +@end deffn +@deffn {} BFD_RELOC_390_GLOB_DAT +Create GOT entry. +@end deffn +@deffn {} BFD_RELOC_390_JMP_SLOT +Create PLT entry. +@end deffn +@deffn {} BFD_RELOC_390_RELATIVE +Adjust by program base. +@end deffn +@deffn {} BFD_RELOC_390_GOTPC +32 bit PC relative offset to GOT. +@end deffn +@deffn {} BFD_RELOC_390_GOT16 +16 bit GOT offset. +@end deffn +@deffn {} BFD_RELOC_390_PC16DBL +PC relative 16 bit shifted by 1. +@end deffn +@deffn {} BFD_RELOC_390_PLT16DBL +16 bit PC rel. PLT shifted by 1. +@end deffn +@deffn {} BFD_RELOC_390_PC32DBL +PC relative 32 bit shifted by 1. +@end deffn +@deffn {} BFD_RELOC_390_PLT32DBL +32 bit PC rel. PLT shifted by 1. +@end deffn +@deffn {} BFD_RELOC_390_GOTPCDBL +32 bit PC rel. GOT shifted by 1. +@end deffn +@deffn {} BFD_RELOC_390_GOT64 +64 bit GOT offset. +@end deffn +@deffn {} BFD_RELOC_390_PLT64 +64 bit PC relative PLT address. +@end deffn +@deffn {} BFD_RELOC_390_GOTENT +32 bit rel. offset to GOT entry. +@end deffn +@deffn {} BFD_RELOC_390_GOTOFF64 +64 bit offset to GOT. +@end deffn +@deffn {} BFD_RELOC_390_GOTPLT12 +12-bit offset to symbol-entry within GOT, with PLT handling. +@end deffn +@deffn {} BFD_RELOC_390_GOTPLT16 +16-bit offset to symbol-entry within GOT, with PLT handling. +@end deffn +@deffn {} BFD_RELOC_390_GOTPLT32 +32-bit offset to symbol-entry within GOT, with PLT handling. +@end deffn +@deffn {} BFD_RELOC_390_GOTPLT64 +64-bit offset to symbol-entry within GOT, with PLT handling. +@end deffn +@deffn {} BFD_RELOC_390_GOTPLTENT +32-bit rel. offset to symbol-entry within GOT, with PLT handling. +@end deffn +@deffn {} BFD_RELOC_390_PLTOFF16 +16-bit rel. offset from the GOT to a PLT entry. +@end deffn +@deffn {} BFD_RELOC_390_PLTOFF32 +32-bit rel. offset from the GOT to a PLT entry. +@end deffn +@deffn {} BFD_RELOC_390_PLTOFF64 +64-bit rel. offset from the GOT to a PLT entry. +@end deffn +@deffn {} BFD_RELOC_390_TLS_LOAD +@deffnx {} BFD_RELOC_390_TLS_GDCALL +@deffnx {} BFD_RELOC_390_TLS_LDCALL +@deffnx {} BFD_RELOC_390_TLS_GD32 +@deffnx {} BFD_RELOC_390_TLS_GD64 +@deffnx {} BFD_RELOC_390_TLS_GOTIE12 +@deffnx {} BFD_RELOC_390_TLS_GOTIE32 +@deffnx {} BFD_RELOC_390_TLS_GOTIE64 +@deffnx {} BFD_RELOC_390_TLS_LDM32 +@deffnx {} BFD_RELOC_390_TLS_LDM64 +@deffnx {} BFD_RELOC_390_TLS_IE32 +@deffnx {} BFD_RELOC_390_TLS_IE64 +@deffnx {} BFD_RELOC_390_TLS_IEENT +@deffnx {} BFD_RELOC_390_TLS_LE32 +@deffnx {} BFD_RELOC_390_TLS_LE64 +@deffnx {} BFD_RELOC_390_TLS_LDO32 +@deffnx {} BFD_RELOC_390_TLS_LDO64 +@deffnx {} BFD_RELOC_390_TLS_DTPMOD +@deffnx {} BFD_RELOC_390_TLS_DTPOFF +@deffnx {} BFD_RELOC_390_TLS_TPOFF +s390 tls relocations. +@end deffn +@deffn {} BFD_RELOC_390_20 +@deffnx {} BFD_RELOC_390_GOT20 +@deffnx {} BFD_RELOC_390_GOTPLT20 +@deffnx {} BFD_RELOC_390_TLS_GOTIE20 +Long displacement extension. +@end deffn +@deffn {} BFD_RELOC_IP2K_FR9 +Scenix IP2K - 9-bit register number / data address +@end deffn +@deffn {} BFD_RELOC_IP2K_BANK +Scenix IP2K - 4-bit register/data bank number +@end deffn +@deffn {} BFD_RELOC_IP2K_ADDR16CJP +Scenix IP2K - low 13 bits of instruction word address +@end deffn +@deffn {} BFD_RELOC_IP2K_PAGE3 +Scenix IP2K - high 3 bits of instruction word address +@end deffn +@deffn {} BFD_RELOC_IP2K_LO8DATA +@deffnx {} BFD_RELOC_IP2K_HI8DATA +@deffnx {} BFD_RELOC_IP2K_EX8DATA +Scenix IP2K - ext/low/high 8 bits of data address +@end deffn +@deffn {} BFD_RELOC_IP2K_LO8INSN +@deffnx {} BFD_RELOC_IP2K_HI8INSN +Scenix IP2K - low/high 8 bits of instruction word address +@end deffn +@deffn {} BFD_RELOC_IP2K_PC_SKIP +Scenix IP2K - even/odd PC modifier to modify snb pcl.0 +@end deffn +@deffn {} BFD_RELOC_IP2K_TEXT +Scenix IP2K - 16 bit word address in text section. +@end deffn +@deffn {} BFD_RELOC_IP2K_FR_OFFSET +Scenix IP2K - 7-bit sp or dp offset +@end deffn +@deffn {} BFD_RELOC_VPE4KMATH_DATA +@deffnx {} BFD_RELOC_VPE4KMATH_INSN +Scenix VPE4K coprocessor - data/insn-space addressing +@end deffn +@deffn {} BFD_RELOC_VTABLE_INHERIT +@deffnx {} BFD_RELOC_VTABLE_ENTRY +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 inheritance 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. +@end deffn +@deffn {} BFD_RELOC_IA64_IMM14 +@deffnx {} BFD_RELOC_IA64_IMM22 +@deffnx {} BFD_RELOC_IA64_IMM64 +@deffnx {} BFD_RELOC_IA64_DIR32MSB +@deffnx {} BFD_RELOC_IA64_DIR32LSB +@deffnx {} BFD_RELOC_IA64_DIR64MSB +@deffnx {} BFD_RELOC_IA64_DIR64LSB +@deffnx {} BFD_RELOC_IA64_GPREL22 +@deffnx {} BFD_RELOC_IA64_GPREL64I +@deffnx {} BFD_RELOC_IA64_GPREL32MSB +@deffnx {} BFD_RELOC_IA64_GPREL32LSB +@deffnx {} BFD_RELOC_IA64_GPREL64MSB +@deffnx {} BFD_RELOC_IA64_GPREL64LSB +@deffnx {} BFD_RELOC_IA64_LTOFF22 +@deffnx {} BFD_RELOC_IA64_LTOFF64I +@deffnx {} BFD_RELOC_IA64_PLTOFF22 +@deffnx {} BFD_RELOC_IA64_PLTOFF64I +@deffnx {} BFD_RELOC_IA64_PLTOFF64MSB +@deffnx {} BFD_RELOC_IA64_PLTOFF64LSB +@deffnx {} BFD_RELOC_IA64_FPTR64I +@deffnx {} BFD_RELOC_IA64_FPTR32MSB +@deffnx {} BFD_RELOC_IA64_FPTR32LSB +@deffnx {} BFD_RELOC_IA64_FPTR64MSB +@deffnx {} BFD_RELOC_IA64_FPTR64LSB +@deffnx {} BFD_RELOC_IA64_PCREL21B +@deffnx {} BFD_RELOC_IA64_PCREL21BI +@deffnx {} BFD_RELOC_IA64_PCREL21M +@deffnx {} BFD_RELOC_IA64_PCREL21F +@deffnx {} BFD_RELOC_IA64_PCREL22 +@deffnx {} BFD_RELOC_IA64_PCREL60B +@deffnx {} BFD_RELOC_IA64_PCREL64I +@deffnx {} BFD_RELOC_IA64_PCREL32MSB +@deffnx {} BFD_RELOC_IA64_PCREL32LSB +@deffnx {} BFD_RELOC_IA64_PCREL64MSB +@deffnx {} BFD_RELOC_IA64_PCREL64LSB +@deffnx {} BFD_RELOC_IA64_LTOFF_FPTR22 +@deffnx {} BFD_RELOC_IA64_LTOFF_FPTR64I +@deffnx {} BFD_RELOC_IA64_LTOFF_FPTR32MSB +@deffnx {} BFD_RELOC_IA64_LTOFF_FPTR32LSB +@deffnx {} BFD_RELOC_IA64_LTOFF_FPTR64MSB +@deffnx {} BFD_RELOC_IA64_LTOFF_FPTR64LSB +@deffnx {} BFD_RELOC_IA64_SEGREL32MSB +@deffnx {} BFD_RELOC_IA64_SEGREL32LSB +@deffnx {} BFD_RELOC_IA64_SEGREL64MSB +@deffnx {} BFD_RELOC_IA64_SEGREL64LSB +@deffnx {} BFD_RELOC_IA64_SECREL32MSB +@deffnx {} BFD_RELOC_IA64_SECREL32LSB +@deffnx {} BFD_RELOC_IA64_SECREL64MSB +@deffnx {} BFD_RELOC_IA64_SECREL64LSB +@deffnx {} BFD_RELOC_IA64_REL32MSB +@deffnx {} BFD_RELOC_IA64_REL32LSB +@deffnx {} BFD_RELOC_IA64_REL64MSB +@deffnx {} BFD_RELOC_IA64_REL64LSB +@deffnx {} BFD_RELOC_IA64_LTV32MSB +@deffnx {} BFD_RELOC_IA64_LTV32LSB +@deffnx {} BFD_RELOC_IA64_LTV64MSB +@deffnx {} BFD_RELOC_IA64_LTV64LSB +@deffnx {} BFD_RELOC_IA64_IPLTMSB +@deffnx {} BFD_RELOC_IA64_IPLTLSB +@deffnx {} BFD_RELOC_IA64_COPY +@deffnx {} BFD_RELOC_IA64_LTOFF22X +@deffnx {} BFD_RELOC_IA64_LDXMOV +@deffnx {} BFD_RELOC_IA64_TPREL14 +@deffnx {} BFD_RELOC_IA64_TPREL22 +@deffnx {} BFD_RELOC_IA64_TPREL64I +@deffnx {} BFD_RELOC_IA64_TPREL64MSB +@deffnx {} BFD_RELOC_IA64_TPREL64LSB +@deffnx {} BFD_RELOC_IA64_LTOFF_TPREL22 +@deffnx {} BFD_RELOC_IA64_DTPMOD64MSB +@deffnx {} BFD_RELOC_IA64_DTPMOD64LSB +@deffnx {} BFD_RELOC_IA64_LTOFF_DTPMOD22 +@deffnx {} BFD_RELOC_IA64_DTPREL14 +@deffnx {} BFD_RELOC_IA64_DTPREL22 +@deffnx {} BFD_RELOC_IA64_DTPREL64I +@deffnx {} BFD_RELOC_IA64_DTPREL32MSB +@deffnx {} BFD_RELOC_IA64_DTPREL32LSB +@deffnx {} BFD_RELOC_IA64_DTPREL64MSB +@deffnx {} BFD_RELOC_IA64_DTPREL64LSB +@deffnx {} BFD_RELOC_IA64_LTOFF_DTPREL22 +Intel IA64 Relocations. +@end deffn +@deffn {} BFD_RELOC_M68HC11_HI8 +Motorola 68HC11 reloc. +This is the 8 bit high part of an absolute address. +@end deffn +@deffn {} BFD_RELOC_M68HC11_LO8 +Motorola 68HC11 reloc. +This is the 8 bit low part of an absolute address. +@end deffn +@deffn {} BFD_RELOC_M68HC11_3B +Motorola 68HC11 reloc. +This is the 3 bit of a value. +@end deffn +@deffn {} BFD_RELOC_M68HC11_RL_JUMP +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 branches to use PC-relative +addressing mode. +@end deffn +@deffn {} BFD_RELOC_M68HC11_RL_GROUP +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. +@end deffn +@deffn {} BFD_RELOC_M68HC11_LO16 +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). +@end deffn +@deffn {} BFD_RELOC_M68HC11_PAGE +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. +@end deffn +@deffn {} BFD_RELOC_M68HC11_24 +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). +@end deffn +@deffn {} BFD_RELOC_M68HC12_5B +Motorola 68HC12 reloc. +This is the 5 bits of a value. +@end deffn +@deffn {} BFD_RELOC_16C_NUM08 +@deffnx {} BFD_RELOC_16C_NUM08_C +@deffnx {} BFD_RELOC_16C_NUM16 +@deffnx {} BFD_RELOC_16C_NUM16_C +@deffnx {} BFD_RELOC_16C_NUM32 +@deffnx {} BFD_RELOC_16C_NUM32_C +@deffnx {} BFD_RELOC_16C_DISP04 +@deffnx {} BFD_RELOC_16C_DISP04_C +@deffnx {} BFD_RELOC_16C_DISP08 +@deffnx {} BFD_RELOC_16C_DISP08_C +@deffnx {} BFD_RELOC_16C_DISP16 +@deffnx {} BFD_RELOC_16C_DISP16_C +@deffnx {} BFD_RELOC_16C_DISP24 +@deffnx {} BFD_RELOC_16C_DISP24_C +@deffnx {} BFD_RELOC_16C_DISP24a +@deffnx {} BFD_RELOC_16C_DISP24a_C +@deffnx {} BFD_RELOC_16C_REG04 +@deffnx {} BFD_RELOC_16C_REG04_C +@deffnx {} BFD_RELOC_16C_REG04a +@deffnx {} BFD_RELOC_16C_REG04a_C +@deffnx {} BFD_RELOC_16C_REG14 +@deffnx {} BFD_RELOC_16C_REG14_C +@deffnx {} BFD_RELOC_16C_REG16 +@deffnx {} BFD_RELOC_16C_REG16_C +@deffnx {} BFD_RELOC_16C_REG20 +@deffnx {} BFD_RELOC_16C_REG20_C +@deffnx {} BFD_RELOC_16C_ABS20 +@deffnx {} BFD_RELOC_16C_ABS20_C +@deffnx {} BFD_RELOC_16C_ABS24 +@deffnx {} BFD_RELOC_16C_ABS24_C +@deffnx {} BFD_RELOC_16C_IMM04 +@deffnx {} BFD_RELOC_16C_IMM04_C +@deffnx {} BFD_RELOC_16C_IMM16 +@deffnx {} BFD_RELOC_16C_IMM16_C +@deffnx {} BFD_RELOC_16C_IMM20 +@deffnx {} BFD_RELOC_16C_IMM20_C +@deffnx {} BFD_RELOC_16C_IMM24 +@deffnx {} BFD_RELOC_16C_IMM24_C +@deffnx {} BFD_RELOC_16C_IMM32 +@deffnx {} BFD_RELOC_16C_IMM32_C +NS CR16C Relocations. +@end deffn +@deffn {} BFD_RELOC_CRX_REL4 +@deffnx {} BFD_RELOC_CRX_REL8 +@deffnx {} BFD_RELOC_CRX_REL8_CMP +@deffnx {} BFD_RELOC_CRX_REL16 +@deffnx {} BFD_RELOC_CRX_REL24 +@deffnx {} BFD_RELOC_CRX_REL32 +@deffnx {} BFD_RELOC_CRX_REGREL12 +@deffnx {} BFD_RELOC_CRX_REGREL22 +@deffnx {} BFD_RELOC_CRX_REGREL28 +@deffnx {} BFD_RELOC_CRX_REGREL32 +@deffnx {} BFD_RELOC_CRX_ABS16 +@deffnx {} BFD_RELOC_CRX_ABS32 +@deffnx {} BFD_RELOC_CRX_NUM8 +@deffnx {} BFD_RELOC_CRX_NUM16 +@deffnx {} BFD_RELOC_CRX_NUM32 +@deffnx {} BFD_RELOC_CRX_IMM16 +@deffnx {} BFD_RELOC_CRX_IMM32 +@deffnx {} BFD_RELOC_CRX_SWITCH8 +@deffnx {} BFD_RELOC_CRX_SWITCH16 +@deffnx {} BFD_RELOC_CRX_SWITCH32 +NS CRX Relocations. +@end deffn +@deffn {} BFD_RELOC_CRIS_BDISP8 +@deffnx {} BFD_RELOC_CRIS_UNSIGNED_5 +@deffnx {} BFD_RELOC_CRIS_SIGNED_6 +@deffnx {} BFD_RELOC_CRIS_UNSIGNED_6 +@deffnx {} BFD_RELOC_CRIS_SIGNED_8 +@deffnx {} BFD_RELOC_CRIS_UNSIGNED_8 +@deffnx {} BFD_RELOC_CRIS_SIGNED_16 +@deffnx {} BFD_RELOC_CRIS_UNSIGNED_16 +@deffnx {} BFD_RELOC_CRIS_LAPCQ_OFFSET +@deffnx {} BFD_RELOC_CRIS_UNSIGNED_4 +These relocs are only used within the CRIS assembler. They are not +(at present) written to any object files. +@end deffn +@deffn {} BFD_RELOC_CRIS_COPY +@deffnx {} BFD_RELOC_CRIS_GLOB_DAT +@deffnx {} BFD_RELOC_CRIS_JUMP_SLOT +@deffnx {} BFD_RELOC_CRIS_RELATIVE +Relocs used in ELF shared libraries for CRIS. +@end deffn +@deffn {} BFD_RELOC_CRIS_32_GOT +32-bit offset to symbol-entry within GOT. +@end deffn +@deffn {} BFD_RELOC_CRIS_16_GOT +16-bit offset to symbol-entry within GOT. +@end deffn +@deffn {} BFD_RELOC_CRIS_32_GOTPLT +32-bit offset to symbol-entry within GOT, with PLT handling. +@end deffn +@deffn {} BFD_RELOC_CRIS_16_GOTPLT +16-bit offset to symbol-entry within GOT, with PLT handling. +@end deffn +@deffn {} BFD_RELOC_CRIS_32_GOTREL +32-bit offset to symbol, relative to GOT. +@end deffn +@deffn {} BFD_RELOC_CRIS_32_PLT_GOTREL +32-bit offset to symbol with PLT entry, relative to GOT. +@end deffn +@deffn {} BFD_RELOC_CRIS_32_PLT_PCREL +32-bit offset to symbol with PLT entry, relative to this relocation. +@end deffn +@deffn {} BFD_RELOC_860_COPY +@deffnx {} BFD_RELOC_860_GLOB_DAT +@deffnx {} BFD_RELOC_860_JUMP_SLOT +@deffnx {} BFD_RELOC_860_RELATIVE +@deffnx {} BFD_RELOC_860_PC26 +@deffnx {} BFD_RELOC_860_PLT26 +@deffnx {} BFD_RELOC_860_PC16 +@deffnx {} BFD_RELOC_860_LOW0 +@deffnx {} BFD_RELOC_860_SPLIT0 +@deffnx {} BFD_RELOC_860_LOW1 +@deffnx {} BFD_RELOC_860_SPLIT1 +@deffnx {} BFD_RELOC_860_LOW2 +@deffnx {} BFD_RELOC_860_SPLIT2 +@deffnx {} BFD_RELOC_860_LOW3 +@deffnx {} BFD_RELOC_860_LOGOT0 +@deffnx {} BFD_RELOC_860_SPGOT0 +@deffnx {} BFD_RELOC_860_LOGOT1 +@deffnx {} BFD_RELOC_860_SPGOT1 +@deffnx {} BFD_RELOC_860_LOGOTOFF0 +@deffnx {} BFD_RELOC_860_SPGOTOFF0 +@deffnx {} BFD_RELOC_860_LOGOTOFF1 +@deffnx {} BFD_RELOC_860_SPGOTOFF1 +@deffnx {} BFD_RELOC_860_LOGOTOFF2 +@deffnx {} BFD_RELOC_860_LOGOTOFF3 +@deffnx {} BFD_RELOC_860_LOPC +@deffnx {} BFD_RELOC_860_HIGHADJ +@deffnx {} BFD_RELOC_860_HAGOT +@deffnx {} BFD_RELOC_860_HAGOTOFF +@deffnx {} BFD_RELOC_860_HAPC +@deffnx {} BFD_RELOC_860_HIGH +@deffnx {} BFD_RELOC_860_HIGOT +@deffnx {} BFD_RELOC_860_HIGOTOFF +Intel i860 Relocations. +@end deffn +@deffn {} BFD_RELOC_OPENRISC_ABS_26 +@deffnx {} BFD_RELOC_OPENRISC_REL_26 +OpenRISC Relocations. +@end deffn +@deffn {} BFD_RELOC_H8_DIR16A8 +@deffnx {} BFD_RELOC_H8_DIR16R8 +@deffnx {} BFD_RELOC_H8_DIR24A8 +@deffnx {} BFD_RELOC_H8_DIR24R8 +@deffnx {} BFD_RELOC_H8_DIR32A16 +H8 elf Relocations. +@end deffn +@deffn {} BFD_RELOC_XSTORMY16_REL_12 +@deffnx {} BFD_RELOC_XSTORMY16_12 +@deffnx {} BFD_RELOC_XSTORMY16_24 +@deffnx {} BFD_RELOC_XSTORMY16_FPTR16 +Sony Xstormy16 Relocations. +@end deffn +@deffn {} BFD_RELOC_XC16X_PAG +@deffnx {} BFD_RELOC_XC16X_POF +@deffnx {} BFD_RELOC_XC16X_SEG +@deffnx {} BFD_RELOC_XC16X_SOF +Infineon Relocations. +@end deffn +@deffn {} BFD_RELOC_VAX_GLOB_DAT +@deffnx {} BFD_RELOC_VAX_JMP_SLOT +@deffnx {} BFD_RELOC_VAX_RELATIVE +Relocations used by VAX ELF. +@end deffn +@deffn {} BFD_RELOC_MT_PC16 +Morpho MT - 16 bit immediate relocation. +@end deffn +@deffn {} BFD_RELOC_MT_HI16 +Morpho MT - Hi 16 bits of an address. +@end deffn +@deffn {} BFD_RELOC_MT_LO16 +Morpho MT - Low 16 bits of an address. +@end deffn +@deffn {} BFD_RELOC_MT_GNU_VTINHERIT +Morpho MT - Used to tell the linker which vtable entries are used. +@end deffn +@deffn {} BFD_RELOC_MT_GNU_VTENTRY +Morpho MT - Used to tell the linker which vtable entries are used. +@end deffn +@deffn {} BFD_RELOC_MT_PCINSN8 +Morpho MT - 8 bit immediate relocation. +@end deffn +@deffn {} BFD_RELOC_MSP430_10_PCREL +@deffnx {} BFD_RELOC_MSP430_16_PCREL +@deffnx {} BFD_RELOC_MSP430_16 +@deffnx {} BFD_RELOC_MSP430_16_PCREL_BYTE +@deffnx {} BFD_RELOC_MSP430_16_BYTE +@deffnx {} BFD_RELOC_MSP430_2X_PCREL +@deffnx {} BFD_RELOC_MSP430_RL_PCREL +msp430 specific relocation codes +@end deffn +@deffn {} BFD_RELOC_IQ2000_OFFSET_16 +@deffnx {} BFD_RELOC_IQ2000_OFFSET_21 +@deffnx {} BFD_RELOC_IQ2000_UHI16 +IQ2000 Relocations. +@end deffn +@deffn {} BFD_RELOC_XTENSA_RTLD +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. +@end deffn +@deffn {} BFD_RELOC_XTENSA_GLOB_DAT +@deffnx {} BFD_RELOC_XTENSA_JMP_SLOT +@deffnx {} BFD_RELOC_XTENSA_RELATIVE +Xtensa relocations for ELF shared objects. +@end deffn +@deffn {} BFD_RELOC_XTENSA_PLT +Xtensa relocation used in ELF object files for symbols that may require +PLT entries. Otherwise, this is just a generic 32-bit relocation. +@end deffn +@deffn {} BFD_RELOC_XTENSA_DIFF8 +@deffnx {} BFD_RELOC_XTENSA_DIFF16 +@deffnx {} BFD_RELOC_XTENSA_DIFF32 +Xtensa relocations to mark the difference of two local symbols. +These are only needed to support linker relaxation and can be ignored +when not relaxing. The field is set to the value of the difference +assuming no relaxation. The relocation encodes the position of the +first symbol so the linker can determine whether to adjust the field +value. +@end deffn +@deffn {} BFD_RELOC_XTENSA_SLOT0_OP +@deffnx {} BFD_RELOC_XTENSA_SLOT1_OP +@deffnx {} BFD_RELOC_XTENSA_SLOT2_OP +@deffnx {} BFD_RELOC_XTENSA_SLOT3_OP +@deffnx {} BFD_RELOC_XTENSA_SLOT4_OP +@deffnx {} BFD_RELOC_XTENSA_SLOT5_OP +@deffnx {} BFD_RELOC_XTENSA_SLOT6_OP +@deffnx {} BFD_RELOC_XTENSA_SLOT7_OP +@deffnx {} BFD_RELOC_XTENSA_SLOT8_OP +@deffnx {} BFD_RELOC_XTENSA_SLOT9_OP +@deffnx {} BFD_RELOC_XTENSA_SLOT10_OP +@deffnx {} BFD_RELOC_XTENSA_SLOT11_OP +@deffnx {} BFD_RELOC_XTENSA_SLOT12_OP +@deffnx {} BFD_RELOC_XTENSA_SLOT13_OP +@deffnx {} BFD_RELOC_XTENSA_SLOT14_OP +Generic Xtensa relocations for instruction operands. Only the slot +number is encoded in the relocation. The relocation applies to the +last PC-relative immediate operand, or if there are no PC-relative +immediates, to the last immediate operand. +@end deffn +@deffn {} BFD_RELOC_XTENSA_SLOT0_ALT +@deffnx {} BFD_RELOC_XTENSA_SLOT1_ALT +@deffnx {} BFD_RELOC_XTENSA_SLOT2_ALT +@deffnx {} BFD_RELOC_XTENSA_SLOT3_ALT +@deffnx {} BFD_RELOC_XTENSA_SLOT4_ALT +@deffnx {} BFD_RELOC_XTENSA_SLOT5_ALT +@deffnx {} BFD_RELOC_XTENSA_SLOT6_ALT +@deffnx {} BFD_RELOC_XTENSA_SLOT7_ALT +@deffnx {} BFD_RELOC_XTENSA_SLOT8_ALT +@deffnx {} BFD_RELOC_XTENSA_SLOT9_ALT +@deffnx {} BFD_RELOC_XTENSA_SLOT10_ALT +@deffnx {} BFD_RELOC_XTENSA_SLOT11_ALT +@deffnx {} BFD_RELOC_XTENSA_SLOT12_ALT +@deffnx {} BFD_RELOC_XTENSA_SLOT13_ALT +@deffnx {} BFD_RELOC_XTENSA_SLOT14_ALT +Alternate Xtensa relocations. Only the slot is encoded in the +relocation. The meaning of these relocations is opcode-specific. +@end deffn +@deffn {} BFD_RELOC_XTENSA_OP0 +@deffnx {} BFD_RELOC_XTENSA_OP1 +@deffnx {} BFD_RELOC_XTENSA_OP2 +Xtensa relocations for backward compatibility. These have all been +replaced by BFD_RELOC_XTENSA_SLOT0_OP. +@end deffn +@deffn {} BFD_RELOC_XTENSA_ASM_EXPAND +Xtensa relocation to mark that the assembler expanded the +instructions from an original target. The expansion size is +encoded in the reloc size. +@end deffn +@deffn {} BFD_RELOC_XTENSA_ASM_SIMPLIFY +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. +@end deffn +@deffn {} BFD_RELOC_Z80_DISP8 +8 bit signed offset in (ix+d) or (iy+d). +@end deffn +@deffn {} BFD_RELOC_Z8K_DISP7 +DJNZ offset. +@end deffn +@deffn {} BFD_RELOC_Z8K_CALLR +CALR offset. +@end deffn +@deffn {} BFD_RELOC_Z8K_IMM4L +4 bit value. +@end deffn + +@example + +typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; +@end example +@findex bfd_reloc_type_lookup +@subsubsection @code{bfd_reloc_type_lookup} +@strong{Synopsis} +@example +reloc_howto_type *bfd_reloc_type_lookup + (bfd *abfd, bfd_reloc_code_real_type code); +@end example +@strong{Description}@* +Return a pointer to a howto structure which, when +invoked, will perform the relocation @var{code} on data from the +architecture noted. + +@findex bfd_default_reloc_type_lookup +@subsubsection @code{bfd_default_reloc_type_lookup} +@strong{Synopsis} +@example +reloc_howto_type *bfd_default_reloc_type_lookup + (bfd *abfd, bfd_reloc_code_real_type code); +@end example +@strong{Description}@* +Provides a default relocation lookup routine for any architecture. + +@findex bfd_get_reloc_code_name +@subsubsection @code{bfd_get_reloc_code_name} +@strong{Synopsis} +@example +const char *bfd_get_reloc_code_name (bfd_reloc_code_real_type code); +@end example +@strong{Description}@* +Provides a printable name for the supplied relocation code. +Useful mainly for printing error messages. + +@findex bfd_generic_relax_section +@subsubsection @code{bfd_generic_relax_section} +@strong{Synopsis} +@example +bfd_boolean bfd_generic_relax_section + (bfd *abfd, + asection *section, + struct bfd_link_info *, + bfd_boolean *); +@end example +@strong{Description}@* +Provides default handling for relaxing for back ends which +don't do relaxing. + +@findex bfd_generic_gc_sections +@subsubsection @code{bfd_generic_gc_sections} +@strong{Synopsis} +@example +bfd_boolean bfd_generic_gc_sections + (bfd *, struct bfd_link_info *); +@end example +@strong{Description}@* +Provides default handling for relaxing for back ends which +don't do section gc -- i.e., does nothing. + +@findex bfd_generic_merge_sections +@subsubsection @code{bfd_generic_merge_sections} +@strong{Synopsis} +@example +bfd_boolean bfd_generic_merge_sections + (bfd *, struct bfd_link_info *); +@end example +@strong{Description}@* +Provides default handling for SEC_MERGE section merging for back ends +which don't have SEC_MERGE support -- i.e., does nothing. + +@findex bfd_generic_get_relocated_section_contents +@subsubsection @code{bfd_generic_get_relocated_section_contents} +@strong{Synopsis} +@example +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 relocatable, + asymbol **symbols); +@end example +@strong{Description}@* +Provides default handling of relocation effort for back ends +which can't be bothered to do it efficiently. + diff --git a/contrib/binutils-2.17/bfd/doc/section.texi b/contrib/binutils-2.17/bfd/doc/section.texi new file mode 100644 index 0000000000..4347679ef4 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/section.texi @@ -0,0 +1,989 @@ +@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 @code{section.c}. + +@menu +* Section Input:: +* Section Output:: +* typedef asection:: +* section prototypes:: +@end menu + +@node 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, @code{a.out} would contain at least +three sections, called @code{.text}, @code{.data} and @code{.bss}. + +Names need not be unique; for example a COFF file may have several +sections named @code{.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 +@code{bfd_make_section}) to the sections attached to an already open +BFD. For example, the linker creates an extra section +@code{COMMON} 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 @code{bfd_get_section_contents} 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. + +@node 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 @code{bfd_set_section_contents}. + +Any program that creates or combines sections (e.g., the assembler +and linker) must use the @code{asection} fields @code{output_section} and +@code{output_offset} to indicate the file sections to which each +section must be written. (If the section is being created from +scratch, @code{output_section} should probably point to the section +itself and @code{output_offset} should probably be zero.) + +The data to be written comes from input sections attached +(via @code{output_section} 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 @code{asection} +structures would look like: + +@example + 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 --------| +@end example + +@subsection Link orders +The data within a section is stored in a @dfn{link_order}. +These are much like the fixups in @code{gas}. 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. + + +@node typedef asection, section prototypes, Section Output, Sections +@subsection typedef asection +Here is the section structure: + + +@example + +typedef struct bfd_section +@{ + /* 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 bfd_section *next; + + /* The previous section in the list belonging to the BFD, or NULL. */ + struct bfd_section *prev; + + /* 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 + + /* A signal to the OS that the section contains read only data. */ +#define SEC_READONLY 0x008 + + /* The section contains code only. */ +#define SEC_CODE 0x010 + + /* The section contains data only. */ +#define SEC_DATA 0x020 + + /* The section will reside in ROM. */ +#define SEC_ROM 0x040 + + /* The section contains constructor information. This section + type is used by the linker to create lists of constructors and + destructors used by @code{g++}. 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., @code{__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 @code{__CTOR_LIST__} and relocate the data + contained within - exactly the operations it would peform on + standard data. */ +#define SEC_CONSTRUCTOR 0x080 + + /* The section has contents - a data section could be + @code{SEC_ALLOC} | @code{SEC_HAS_CONTENTS}; a debug section could be + @code{SEC_HAS_CONTENTS} */ +#define SEC_HAS_CONTENTS 0x100 + + /* An instruction to the linker to not output the section + even if it has information which would normally be written. */ +#define SEC_NEVER_LOAD 0x200 + + /* The section contains thread local data. */ +#define SEC_THREAD_LOCAL 0x400 + + /* 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 0x800 + + /* 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 0x1000 + + /* 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 0x2000 + + /* 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 0x4000 + + /* 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 0x8000 + + /* 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 0x10000 + + /* 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 0x20000 + + /* If SEC_LINK_ONCE is set, this bitfield describes how the linker + should handle duplicate sections. */ +#define SEC_LINK_DUPLICATES 0x40000 + + /* 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 0x80000 + + /* 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 0x100000 + + /* 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 \ + (SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE) + + /* 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 0x200000 + + /* This section should not be subject to garbage collection. */ +#define SEC_KEEP 0x400000 + + /* This section contains "short" data, and should be placed + "near" the GP. */ +#define SEC_SMALL_DATA 0x800000 + + /* Attempt to merge identical entities in the section. + Entity size is given in the entsize field. */ +#define SEC_MERGE 0x1000000 + + /* 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 0x2000000 + + /* This section contains data about section groups. */ +#define SEC_GROUP 0x4000000 + + /* 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 0x10000000 + + /* This section contains data which may be shared with other + executables or shared objects. This is for COFF only. */ +#define SEC_COFF_SHARED 0x20000000 + + /* 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. This is for TI + TMS320C54X only. */ +#define SEC_TIC54X_BLOCK 0x40000000 + + /* Conditionally link this section; do not link if there are no + references found to any symbol in the section. This is for TI + TMS320C54X only. */ +#define SEC_TIC54X_CLINK 0x80000000 + + /* End of section flags. */ + + /* Some internal packed boolean fields. */ + + /* See the vma field. */ + unsigned int user_set_vma : 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; + + /* Mark flags used by some linker backends for garbage collection. */ + unsigned int gc_mark : 1; + unsigned int gc_mark_from_eh : 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. The generic code doesn't touch + these fields. */ + + /* Nonzero if this section has TLS related relocations. */ + unsigned int has_tls_reloc:1; + + /* Nonzero if this section has a gp reloc. */ + unsigned int has_gp_reloc:1; + + /* Nonzero if this section needs the relax finalize pass. */ + unsigned int need_finalize_relax:1; + + /* Whether relocations have been processed. */ + unsigned int reloc_done : 1; + + /* 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 @code{a.out}, where + the default address for @code{.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 @code{.bss}). */ + bfd_size_type size; + + /* For input sections, the original size on disk of the section, in + octets. This field is used by the linker relaxation code. It is + currently only set for sections where the linker relaxation scheme + doesn't cache altered section and reloc contents (stabs, eh_frame, + SEC_MERGE, some coff relaxing targets), and thus the original size + needs to be kept to read the section multiple times. + For output sections, rawsize holds the section size calculated on + a previous linker relaxation pass. */ + bfd_size_type rawsize; + + /* 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 bfd_section *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. */ + void *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; + + /* Points to the kept section if this section is a link-once section, + and is discarded. */ + struct bfd_section *kept_section; + + /* 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; + + void *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 bfd_symbol *symbol; + struct bfd_symbol **symbol_ptr_ptr; + + /* Early in the link process, map_head and map_tail are used to build + a list of input sections attached to an output section. Later, + output sections use these fields for a list of bfd_link_order + structs. */ + union @{ + struct bfd_link_order *link_order; + struct bfd_section *s; + @} map_head, map_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 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 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 asection bfd_com_section; +#define bfd_com_section_ptr ((asection *) &bfd_com_section) +/* Pointer to the indirect section. */ +extern 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 bfd_symbol * const bfd_abs_symbol; +extern const struct bfd_symbol * const bfd_com_symbol; +extern const struct bfd_symbol * const bfd_und_symbol; +extern const struct bfd_symbol * const bfd_ind_symbol; + +/* 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, S) \ + do \ + @{ \ + asection *_s = S; \ + asection *_next = _s->next; \ + asection *_prev = _s->prev; \ + if (_prev) \ + _prev->next = _next; \ + else \ + (ABFD)->sections = _next; \ + if (_next) \ + _next->prev = _prev; \ + else \ + (ABFD)->section_last = _prev; \ + @} \ + while (0) +#define bfd_section_list_append(ABFD, S) \ + do \ + @{ \ + asection *_s = S; \ + bfd *_abfd = ABFD; \ + _s->next = NULL; \ + if (_abfd->section_last) \ + @{ \ + _s->prev = _abfd->section_last; \ + _abfd->section_last->next = _s; \ + @} \ + else \ + @{ \ + _s->prev = NULL; \ + _abfd->sections = _s; \ + @} \ + _abfd->section_last = _s; \ + @} \ + while (0) +#define bfd_section_list_prepend(ABFD, S) \ + do \ + @{ \ + asection *_s = S; \ + bfd *_abfd = ABFD; \ + _s->prev = NULL; \ + if (_abfd->sections) \ + @{ \ + _s->next = _abfd->sections; \ + _abfd->sections->prev = _s; \ + @} \ + else \ + @{ \ + _s->next = NULL; \ + _abfd->section_last = _s; \ + @} \ + _abfd->sections = _s; \ + @} \ + while (0) +#define bfd_section_list_insert_after(ABFD, A, S) \ + do \ + @{ \ + asection *_a = A; \ + asection *_s = S; \ + asection *_next = _a->next; \ + _s->next = _next; \ + _s->prev = _a; \ + _a->next = _s; \ + if (_next) \ + _next->prev = _s; \ + else \ + (ABFD)->section_last = _s; \ + @} \ + while (0) +#define bfd_section_list_insert_before(ABFD, B, S) \ + do \ + @{ \ + asection *_b = B; \ + asection *_s = S; \ + asection *_prev = _b->prev; \ + _s->prev = _prev; \ + _s->next = _b; \ + _b->prev = _s; \ + if (_prev) \ + _prev->next = _s; \ + else \ + (ABFD)->sections = _s; \ + @} \ + while (0) +#define bfd_section_removed_from_list(ABFD, S) \ + ((S)->next == NULL ? (ABFD)->section_last != (S) : (S)->next->prev != (S)) + +#define BFD_FAKE_SECTION(SEC, FLAGS, SYM, SYM_PTR, NAME, IDX) \ + /* name, id, index, next, prev, flags, user_set_vma, */ \ + @{ NAME, IDX, 0, NULL, NULL, FLAGS, 0, \ + \ + /* linker_mark, linker_has_input, gc_mark, gc_mark_from_eh, */ \ + 0, 0, 1, 0, \ + \ + /* segment_mark, sec_info_type, use_rela_p, has_tls_reloc, */ \ + 0, 0, 0, 0, \ + \ + /* has_gp_reloc, need_finalize_relax, reloc_done, */ \ + 0, 0, 0, \ + \ + /* vma, lma, size, rawsize */ \ + 0, 0, 0, 0, \ + \ + /* output_offset, output_section, alignment_power, */ \ + 0, (struct bfd_section *) &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, kept_section, moving_line_filepos, */ \ + 0, NULL, 0, \ + \ + /* target_index, used_by_bfd, constructor_chain, owner, */ \ + 0, NULL, NULL, NULL, \ + \ + /* symbol, */ \ + (struct bfd_symbol *) SYM, \ + \ + /* symbol_ptr_ptr, */ \ + (struct bfd_symbol **) SYM_PTR, \ + \ + /* map_head, map_tail */ \ + @{ NULL @}, @{ NULL @} \ + @} + +@end example + +@node section prototypes, , typedef asection, Sections +@subsection Section prototypes +These are the functions exported by the section handling part of BFD. + +@findex bfd_section_list_clear +@subsubsection @code{bfd_section_list_clear} +@strong{Synopsis} +@example +void bfd_section_list_clear (bfd *); +@end example +@strong{Description}@* +Clears the section list, and also resets the section count and +hash table entries. + +@findex bfd_get_section_by_name +@subsubsection @code{bfd_get_section_by_name} +@strong{Synopsis} +@example +asection *bfd_get_section_by_name (bfd *abfd, const char *name); +@end example +@strong{Description}@* +Run through @var{abfd} and return the one of the +@code{asection}s whose name matches @var{name}, otherwise @code{NULL}. +@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 @code{bfd_map_over_sections} and +@code{strcmp} on the name (or better yet, base it on the section flags +or something else) for each section. + +@findex bfd_get_section_by_name_if +@subsubsection @code{bfd_get_section_by_name_if} +@strong{Synopsis} +@example +asection *bfd_get_section_by_name_if + (bfd *abfd, + const char *name, + bfd_boolean (*func) (bfd *abfd, asection *sect, void *obj), + void *obj); +@end example +@strong{Description}@* +Call the provided function @var{func} for each section +attached to the BFD @var{abfd} whose name matches @var{name}, +passing @var{obj} as an argument. The function will be called +as if by + +@example + func (abfd, the_section, obj); +@end example + +It returns the first section for which @var{func} returns true, +otherwise @code{NULL}. + +@findex bfd_get_unique_section_name +@subsubsection @code{bfd_get_unique_section_name} +@strong{Synopsis} +@example +char *bfd_get_unique_section_name + (bfd *abfd, const char *templat, int *count); +@end example +@strong{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. + +@findex bfd_make_section_old_way +@subsubsection @code{bfd_make_section_old_way} +@strong{Synopsis} +@example +asection *bfd_make_section_old_way (bfd *abfd, const char *name); +@end example +@strong{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: +@itemize @bullet + +@item +@code{bfd_error_invalid_operation} - +If output has already started for this BFD. +@item +@code{bfd_error_no_memory} - +If memory allocation fails. +@end itemize + +@findex bfd_make_section_anyway_with_flags +@subsubsection @code{bfd_make_section_anyway_with_flags} +@strong{Synopsis} +@example +asection *bfd_make_section_anyway_with_flags + (bfd *abfd, const char *name, flagword flags); +@end example +@strong{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. Also set the attributes of the +new section to the value @var{flags}. + +Return @code{NULL} and set @code{bfd_error} on error; possible errors are: +@itemize @bullet + +@item +@code{bfd_error_invalid_operation} - If output has already started for @var{abfd}. +@item +@code{bfd_error_no_memory} - If memory allocation fails. +@end itemize + +@findex bfd_make_section_anyway +@subsubsection @code{bfd_make_section_anyway} +@strong{Synopsis} +@example +asection *bfd_make_section_anyway (bfd *abfd, const char *name); +@end example +@strong{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 @code{NULL} and set @code{bfd_error} on error; possible errors are: +@itemize @bullet + +@item +@code{bfd_error_invalid_operation} - If output has already started for @var{abfd}. +@item +@code{bfd_error_no_memory} - If memory allocation fails. +@end itemize + +@findex bfd_make_section_with_flags +@subsubsection @code{bfd_make_section_with_flags} +@strong{Synopsis} +@example +asection *bfd_make_section_with_flags + (bfd *, const char *name, flagword flags); +@end example +@strong{Description}@* +Like @code{bfd_make_section_anyway}, but return @code{NULL} (without calling +bfd_set_error ()) without changing the section chain if there is already a +section named @var{name}. Also set the attributes of the new section to +the value @var{flags}. If there is an error, return @code{NULL} and set +@code{bfd_error}. + +@findex bfd_make_section +@subsubsection @code{bfd_make_section} +@strong{Synopsis} +@example +asection *bfd_make_section (bfd *, const char *name); +@end example +@strong{Description}@* +Like @code{bfd_make_section_anyway}, but return @code{NULL} (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 @code{NULL} and set +@code{bfd_error}. + +@findex bfd_set_section_flags +@subsubsection @code{bfd_set_section_flags} +@strong{Synopsis} +@example +bfd_boolean bfd_set_section_flags + (bfd *abfd, asection *sec, flagword flags); +@end example +@strong{Description}@* +Set the attributes of the section @var{sec} in the BFD +@var{abfd} to the value @var{flags}. Return @code{TRUE} on success, +@code{FALSE} on error. Possible error returns are: + +@itemize @bullet + +@item +@code{bfd_error_invalid_operation} - +The section cannot have one or more of the attributes +requested. For example, a .bss section in @code{a.out} may not +have the @code{SEC_HAS_CONTENTS} field set. +@end itemize + +@findex bfd_map_over_sections +@subsubsection @code{bfd_map_over_sections} +@strong{Synopsis} +@example +void bfd_map_over_sections + (bfd *abfd, + void (*func) (bfd *abfd, asection *sect, void *obj), + void *obj); +@end example +@strong{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 + +@example + func (abfd, the_section, obj); +@end example + +This is the preferred method for iterating over sections; an +alternative would be to use a loop: + +@example + section *p; + for (p = abfd->sections; p != NULL; p = p->next) + func (abfd, p, ...) +@end example + +@findex bfd_sections_find_if +@subsubsection @code{bfd_sections_find_if} +@strong{Synopsis} +@example +asection *bfd_sections_find_if + (bfd *abfd, + bfd_boolean (*operation) (bfd *abfd, asection *sect, void *obj), + void *obj); +@end example +@strong{Description}@* +Call the provided function @var{operation} for each section +attached to the BFD @var{abfd}, passing @var{obj} as an +argument. The function will be called as if by + +@example + operation (abfd, the_section, obj); +@end example + +It returns the first section for which @var{operation} returns true. + +@findex bfd_set_section_size +@subsubsection @code{bfd_set_section_size} +@strong{Synopsis} +@example +bfd_boolean bfd_set_section_size + (bfd *abfd, asection *sec, bfd_size_type val); +@end example +@strong{Description}@* +Set @var{sec} to the size @var{val}. If the operation is +ok, then @code{TRUE} is returned, else @code{FALSE}. + +Possible error returns: +@itemize @bullet + +@item +@code{bfd_error_invalid_operation} - +Writing has started to the BFD, so setting the size is invalid. +@end itemize + +@findex bfd_set_section_contents +@subsubsection @code{bfd_set_section_contents} +@strong{Synopsis} +@example +bfd_boolean bfd_set_section_contents + (bfd *abfd, asection *section, const void *data, + file_ptr offset, bfd_size_type count); +@end example +@strong{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 @code{TRUE} is returned, else @code{FALSE}. Possible error +returns are: +@itemize @bullet + +@item +@code{bfd_error_no_contents} - +The output section does not have the @code{SEC_HAS_CONTENTS} +attribute, so nothing can be written to it. +@item +and some more too +@end itemize +This routine is front end to the back end function +@code{_bfd_set_section_contents}. + +@findex bfd_get_section_contents +@subsubsection @code{bfd_get_section_contents} +@strong{Synopsis} +@example +bfd_boolean bfd_get_section_contents + (bfd *abfd, asection *section, void *location, file_ptr offset, + bfd_size_type count); +@end example +@strong{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 @code{SEC_CONSTRUCTOR} +flag set are requested or if the section does not have the +@code{SEC_HAS_CONTENTS} flag set, then the @var{location} is filled +with zeroes. If no errors occur, @code{TRUE} is returned, else +@code{FALSE}. + +@findex bfd_malloc_and_get_section +@subsubsection @code{bfd_malloc_and_get_section} +@strong{Synopsis} +@example +bfd_boolean bfd_malloc_and_get_section + (bfd *abfd, asection *section, bfd_byte **buf); +@end example +@strong{Description}@* +Read all data from @var{section} in BFD @var{abfd} +into a buffer, *@var{buf}, malloc'd by this function. + +@findex bfd_copy_private_section_data +@subsubsection @code{bfd_copy_private_section_data} +@strong{Synopsis} +@example +bfd_boolean bfd_copy_private_section_data + (bfd *ibfd, asection *isec, bfd *obfd, asection *osec); +@end example +@strong{Description}@* +Copy private section information from @var{isec} in the BFD +@var{ibfd} to the section @var{osec} in the BFD @var{obfd}. +Return @code{TRUE} on success, @code{FALSE} on error. Possible error +returns are: + +@itemize @bullet + +@item +@code{bfd_error_no_memory} - +Not enough memory exists to create private data for @var{osec}. +@end itemize +@example +#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \ + BFD_SEND (obfd, _bfd_copy_private_section_data, \ + (ibfd, isection, obfd, osection)) +@end example + +@findex bfd_generic_is_group_section +@subsubsection @code{bfd_generic_is_group_section} +@strong{Synopsis} +@example +bfd_boolean bfd_generic_is_group_section (bfd *, const asection *sec); +@end example +@strong{Description}@* +Returns TRUE if @var{sec} is a member of a group. + +@findex bfd_generic_discard_group +@subsubsection @code{bfd_generic_discard_group} +@strong{Synopsis} +@example +bfd_boolean bfd_generic_discard_group (bfd *abfd, asection *group); +@end example +@strong{Description}@* +Remove all members of @var{group} from the output. + diff --git a/contrib/binutils-2.17/bfd/doc/syms.texi b/contrib/binutils-2.17/bfd/doc/syms.texi new file mode 100644 index 0000000000..dc56bbc7e1 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/syms.texi @@ -0,0 +1,461 @@ +@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 @code{asymbol} 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 @code{asymbol}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 + +@node 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: + +@example + 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 = 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]); +@end example + +All storage for the symbols themselves is in an objalloc +connected to the BFD; it is freed when the BFD is closed. + +@node 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 @code{bfd_make_empty_symbol}. Here is an +example showing the creation of a symbol table with only one element: + +@example + #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] = 0; + + bfd_set_symtab (abfd, ptrs, 1); + bfd_close (abfd); + return 0; + @} + + ./makesym + nm foo + 00012345 A dummy_symbol +@end example + +Many formats cannot represent arbitrary symbol information; for +instance, the @code{a.out} object format does not allow an +arbitrary number of sections. A symbol pointing to a section +which is not one of @code{.text}, @code{.data} or @code{.bss} cannot +be described. + +@node 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 @code{bfd_read_minisymbols} function will read the symbols +into memory in an internal form. It will return a @code{void *} +pointer to a block of memory, a symbol count, and the size of +each symbol. The pointer is allocated using @code{malloc}, and +should be freed by the caller when it is no longer needed. + +The function @code{bfd_minisymbol_to_symbol} will take a pointer +to a minisymbol, and a pointer to a structure returned by +@code{bfd_make_empty_symbol}, and return a @code{asymbol} structure. +The return value may or may not be the same as the value from +@code{bfd_make_empty_symbol} which was passed in. + + +@node typedef asymbol, symbol handling functions, Mini Symbols, Symbols +@subsection typedef asymbol +An @code{asymbol} has the form: + + +@example + +typedef struct bfd_symbol +@{ + /* 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; @code{static} in @code{C}. The value + is the offset into the section of the data. */ +#define BSF_LOCAL 0x01 + + /* The symbol has global scope; initialized data in @code{C}. 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: + @code{BSF_LOCAL}, @code{BSF_FORT_COMM}, @code{BSF_UNDEFINED} or + @code{BSF_GLOBAL}. */ + + /* The symbol is a debugging record. The value has an arbitrary + 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 @code{ISFCN} symbol + which is also @code{C_EXT} 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 bfd_section *section; + + /* Back end special data. */ + union + @{ + void *p; + bfd_vma i; + @} + udata; +@} +asymbol; + +@end example + +@node symbol handling functions, , typedef asymbol, Symbols +@subsection Symbol handling functions + + +@findex bfd_get_symtab_upper_bound +@subsubsection @code{bfd_get_symtab_upper_bound} +@strong{Description}@* +Return the number of bytes required to store a vector of pointers +to @code{asymbols} 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. +@example +#define bfd_get_symtab_upper_bound(abfd) \ + BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd)) + +@end example + +@findex bfd_is_local_label +@subsubsection @code{bfd_is_local_label} +@strong{Synopsis} +@example +bfd_boolean bfd_is_local_label (bfd *abfd, asymbol *sym); +@end example +@strong{Description}@* +Return TRUE if the given symbol @var{sym} in the BFD @var{abfd} is +a compiler generated local label, else return FALSE. + +@findex bfd_is_local_label_name +@subsubsection @code{bfd_is_local_label_name} +@strong{Synopsis} +@example +bfd_boolean bfd_is_local_label_name (bfd *abfd, const char *name); +@end example +@strong{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. +@example +#define bfd_is_local_label_name(abfd, name) \ + BFD_SEND (abfd, _bfd_is_local_label_name, (abfd, name)) + +@end example + +@findex bfd_is_target_special_symbol +@subsubsection @code{bfd_is_target_special_symbol} +@strong{Synopsis} +@example +bfd_boolean bfd_is_target_special_symbol (bfd *abfd, asymbol *sym); +@end example +@strong{Description}@* +Return TRUE iff a symbol @var{sym} in the BFD @var{abfd} is something +special to the particular target represented by the BFD. Such symbols +should normally not be mentioned to the user. +@example +#define bfd_is_target_special_symbol(abfd, sym) \ + BFD_SEND (abfd, _bfd_is_target_special_symbol, (abfd, sym)) + +@end example + +@findex bfd_canonicalize_symtab +@subsubsection @code{bfd_canonicalize_symtab} +@strong{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. +@example +#define bfd_canonicalize_symtab(abfd, location) \ + BFD_SEND (abfd, _bfd_canonicalize_symtab, (abfd, location)) + +@end example + +@findex bfd_set_symtab +@subsubsection @code{bfd_set_symtab} +@strong{Synopsis} +@example +bfd_boolean bfd_set_symtab + (bfd *abfd, asymbol **location, unsigned int count); +@end example +@strong{Description}@* +Arrange that when the output BFD @var{abfd} is closed, +the table @var{location} of @var{count} pointers to symbols +will be written. + +@findex bfd_print_symbol_vandf +@subsubsection @code{bfd_print_symbol_vandf} +@strong{Synopsis} +@example +void bfd_print_symbol_vandf (bfd *abfd, void *file, asymbol *symbol); +@end example +@strong{Description}@* +Print the value and flags of the @var{symbol} supplied to the +stream @var{file}. + +@findex bfd_make_empty_symbol +@subsubsection @code{bfd_make_empty_symbol} +@strong{Description}@* +Create a new @code{asymbol} 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 @code{asymbol}. Building your own +@code{asymbol} and pointing to it will not create the private +information, and will cause problems later on. +@example +#define bfd_make_empty_symbol(abfd) \ + BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) + +@end example + +@findex _bfd_generic_make_empty_symbol +@subsubsection @code{_bfd_generic_make_empty_symbol} +@strong{Synopsis} +@example +asymbol *_bfd_generic_make_empty_symbol (bfd *); +@end example +@strong{Description}@* +Create a new @code{asymbol} 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. + +@findex bfd_make_debug_symbol +@subsubsection @code{bfd_make_debug_symbol} +@strong{Description}@* +Create a new @code{asymbol} structure for the BFD @var{abfd}, +to be used as a debugging symbol. Further details of its use have +yet to be worked out. +@example +#define bfd_make_debug_symbol(abfd,ptr,size) \ + BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) + +@end example + +@findex bfd_decode_symclass +@subsubsection @code{bfd_decode_symclass} +@strong{Description}@* +Return a character corresponding to the symbol +class of @var{symbol}, or '?' for an unknown class. + +@strong{Synopsis} +@example +int bfd_decode_symclass (asymbol *symbol); +@end example +@findex bfd_is_undefined_symclass +@subsubsection @code{bfd_is_undefined_symclass} +@strong{Description}@* +Returns non-zero if the class symbol returned by +bfd_decode_symclass represents an undefined symbol. +Returns zero otherwise. + +@strong{Synopsis} +@example +bfd_boolean bfd_is_undefined_symclass (int symclass); +@end example +@findex bfd_symbol_info +@subsubsection @code{bfd_symbol_info} +@strong{Description}@* +Fill in the basic info about symbol that nm needs. +Additional info may be added by the back-ends after +calling this function. + +@strong{Synopsis} +@example +void bfd_symbol_info (asymbol *symbol, symbol_info *ret); +@end example +@findex bfd_copy_private_symbol_data +@subsubsection @code{bfd_copy_private_symbol_data} +@strong{Synopsis} +@example +bfd_boolean bfd_copy_private_symbol_data + (bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym); +@end example +@strong{Description}@* +Copy private symbol information from @var{isym} in the BFD +@var{ibfd} to the symbol @var{osym} in the BFD @var{obfd}. +Return @code{TRUE} on success, @code{FALSE} on error. Possible error +returns are: + +@itemize @bullet + +@item +@code{bfd_error_no_memory} - +Not enough memory exists to create private data for @var{osec}. +@end itemize +@example +#define bfd_copy_private_symbol_data(ibfd, isymbol, obfd, osymbol) \ + BFD_SEND (obfd, _bfd_copy_private_symbol_data, \ + (ibfd, isymbol, obfd, osymbol)) + +@end example + diff --git a/contrib/binutils-2.17/bfd/doc/targets.texi b/contrib/binutils-2.17/bfd/doc/targets.texi new file mode 100644 index 0000000000..a85c849110 --- /dev/null +++ b/contrib/binutils-2.17/bfd/doc/targets.texi @@ -0,0 +1,551 @@ +@section Targets + + +@strong{Description}@* +Each port of BFD to a different machine requires 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 @code{bfd_openr}, its format and +target are unknown. BFD uses various mechanisms to determine +how to interpret the file. The operations performed are: + +@itemize @bullet + +@item +Create a BFD by calling the internal routine +@code{_bfd_new_bfd}, then call @code{bfd_find_target} with the +target string supplied to @code{bfd_openr} and the new BFD pointer. + +@item +If a null target string was provided to @code{bfd_find_target}, +look up the environment variable @code{GNUTARGET} and use +that as the target string. + +@item +If the target string is still @code{NULL}, or the target string is +@code{default}, then use the first item in the target vector +as the target type, and set @code{target_defaulted} in the BFD to +cause @code{bfd_check_format} to loop through all the targets. +@xref{bfd_target}. @xref{Formats}. + +@item +Otherwise, inspect the elements in the target vector +one by one, until a match on target name is found. When found, +use it. + +@item +Otherwise return the error @code{bfd_error_invalid_target} to +@code{bfd_openr}. + +@item +@code{bfd_openr} attempts to open the file using +@code{bfd_open_file}, and returns the BFD. +@end itemize +Once the BFD has been opened and the target selected, the file +format may be determined. This is done by calling +@code{bfd_check_format} on the BFD with a suggested format. +If @code{target_defaulted} has been set, each possible target +type is tried to see if it recognizes the specified format. +@code{bfd_check_format} returns @code{TRUE} when the caller guesses right. +@menu +* bfd_target:: +@end menu + +@node bfd_target, , Targets, Targets + +@subsection bfd_target + + +@strong{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 @code{xvec} +member. + +The macros below are used to dispatch to functions through the +@code{bfd_target} 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. +@example +#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 +@end example +For operations which index on the BFD format: +@example +#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 + +@end example +This is the structure which defines the type of BFD this is. The +@code{xvec} member of the struct @code{bfd} 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! +@example +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 @code{BFD_NO_FLAGS}, @code{HAS_RELOC}, ...@code{D_PAGED}. */ + flagword object_flags; + + /* A mask of all the flags which a section may have set - from + the set @code{SEC_NO_FLAGS}, @code{SEC_ALLOC}, ...@code{SET_NEVER_LOAD}. */ + 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 as the first argument. + Certain other handlers could do the same. */ + bfd_uint64_t (*bfd_getx64) (const void *); + bfd_int64_t (*bfd_getx_signed_64) (const void *); + void (*bfd_putx64) (bfd_uint64_t, void *); + bfd_vma (*bfd_getx32) (const void *); + bfd_signed_vma (*bfd_getx_signed_32) (const void *); + void (*bfd_putx32) (bfd_vma, void *); + bfd_vma (*bfd_getx16) (const void *); + bfd_signed_vma (*bfd_getx_signed_16) (const void *); + void (*bfd_putx16) (bfd_vma, void *); + + /* Byte swapping for the headers. */ + bfd_uint64_t (*bfd_h_getx64) (const void *); + bfd_int64_t (*bfd_h_getx_signed_64) (const void *); + void (*bfd_h_putx64) (bfd_uint64_t, void *); + bfd_vma (*bfd_h_getx32) (const void *); + bfd_signed_vma (*bfd_h_getx_signed_32) (const void *); + void (*bfd_h_putx32) (bfd_vma, void *); + bfd_vma (*bfd_h_getx16) (const void *); + bfd_signed_vma (*bfd_h_getx_signed_16) (const void *); + void (*bfd_h_putx16) (bfd_vma, void *); + + /* 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 @code{bfd_target *} or zero. */ + const struct bfd_target *(*_bfd_check_format[bfd_type_end]) (bfd *); + + /* Set the format of a file being written. */ + bfd_boolean (*_bfd_set_format[bfd_type_end]) (bfd *); + + /* Write cached information into a file being written, at @code{bfd_close}. */ + bfd_boolean (*_bfd_write_contents[bfd_type_end]) (bfd *); + +@end example +The general target vector. These vectors are initialized using the +BFD_JUMP_TABLE macros. +@example + + /* Generic entry points. */ +#define BFD_JUMP_TABLE_GENERIC(NAME) \ + NAME##_close_and_cleanup, \ + NAME##_bfd_free_cached_info, \ + NAME##_new_section_hook, \ + NAME##_get_section_contents, \ + NAME##_get_section_contents_in_window + + /* Called when the BFD is being closed to do any necessary cleanup. */ + bfd_boolean (*_close_and_cleanup) (bfd *); + /* Ask the BFD to free all cached information. */ + bfd_boolean (*_bfd_free_cached_info) (bfd *); + /* Called when a new section is created. */ + bfd_boolean (*_new_section_hook) (bfd *, sec_ptr); + /* Read the contents of a section. */ + bfd_boolean (*_bfd_get_section_contents) + (bfd *, sec_ptr, void *, file_ptr, bfd_size_type); + bfd_boolean (*_bfd_get_section_contents_in_window) + (bfd *, sec_ptr, bfd_window *, file_ptr, bfd_size_type); + + /* Entry points to copy private data. */ +#define BFD_JUMP_TABLE_COPY(NAME) \ + NAME##_bfd_copy_private_bfd_data, \ + NAME##_bfd_merge_private_bfd_data, \ + _bfd_generic_init_private_section_data, \ + NAME##_bfd_copy_private_section_data, \ + NAME##_bfd_copy_private_symbol_data, \ + NAME##_bfd_copy_private_header_data, \ + NAME##_bfd_set_private_flags, \ + 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) (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) (bfd *, bfd *); + /* Called to initialize BFD private section data from one object file + to another. */ +#define bfd_init_private_section_data(ibfd, isec, obfd, osec, link_info) \ + BFD_SEND (obfd, _bfd_init_private_section_data, (ibfd, isec, obfd, osec, link_info)) + bfd_boolean (*_bfd_init_private_section_data) + (bfd *, sec_ptr, bfd *, sec_ptr, struct bfd_link_info *); + /* Called to copy BFD private section data from one object file + to another. */ + bfd_boolean (*_bfd_copy_private_section_data) + (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) + (bfd *, asymbol *, bfd *, asymbol *); + /* Called to copy BFD private header data from one object file + to another. */ + bfd_boolean (*_bfd_copy_private_header_data) + (bfd *, bfd *); + /* Called to set private backend flags. */ + bfd_boolean (*_bfd_set_private_flags) (bfd *, flagword); + + /* Called to print private BFD data. */ + bfd_boolean (*_bfd_print_private_bfd_data) (bfd *, void *); + + /* Core file entry points. */ +#define BFD_JUMP_TABLE_CORE(NAME) \ + NAME##_core_file_failing_command, \ + NAME##_core_file_failing_signal, \ + NAME##_core_file_matches_executable_p + + char * (*_core_file_failing_command) (bfd *); + int (*_core_file_failing_signal) (bfd *); + bfd_boolean (*_core_file_matches_executable_p) (bfd *, bfd *); + + /* Archive entry points. */ +#define BFD_JUMP_TABLE_ARCHIVE(NAME) \ + NAME##_slurp_armap, \ + NAME##_slurp_extended_name_table, \ + NAME##_construct_extended_name_table, \ + NAME##_truncate_arname, \ + NAME##_write_armap, \ + NAME##_read_ar_hdr, \ + NAME##_openr_next_archived_file, \ + NAME##_get_elt_at_index, \ + NAME##_generic_stat_arch_elt, \ + NAME##_update_armap_timestamp + + bfd_boolean (*_bfd_slurp_armap) (bfd *); + bfd_boolean (*_bfd_slurp_extended_name_table) (bfd *); + bfd_boolean (*_bfd_construct_extended_name_table) + (bfd *, char **, bfd_size_type *, const char **); + void (*_bfd_truncate_arname) (bfd *, const char *, char *); + bfd_boolean (*write_armap) + (bfd *, unsigned int, struct orl *, unsigned int, int); + void * (*_bfd_read_ar_hdr_fn) (bfd *); + bfd * (*openr_next_archived_file) (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) (bfd *, symindex); + int (*_bfd_stat_arch_elt) (bfd *, struct stat *); + bfd_boolean (*_bfd_update_armap_timestamp) (bfd *); + + /* Entry points used for symbols. */ +#define BFD_JUMP_TABLE_SYMBOLS(NAME) \ + NAME##_get_symtab_upper_bound, \ + NAME##_canonicalize_symtab, \ + NAME##_make_empty_symbol, \ + NAME##_print_symbol, \ + NAME##_get_symbol_info, \ + NAME##_bfd_is_local_label_name, \ + NAME##_bfd_is_target_special_symbol, \ + NAME##_get_lineno, \ + NAME##_find_nearest_line, \ + _bfd_generic_find_line, \ + NAME##_find_inliner_info, \ + NAME##_bfd_make_debug_symbol, \ + NAME##_read_minisymbols, \ + NAME##_minisymbol_to_symbol + + long (*_bfd_get_symtab_upper_bound) (bfd *); + long (*_bfd_canonicalize_symtab) + (bfd *, struct bfd_symbol **); + struct bfd_symbol * + (*_bfd_make_empty_symbol) (bfd *); + void (*_bfd_print_symbol) + (bfd *, void *, struct bfd_symbol *, 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) + (bfd *, struct bfd_symbol *, 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) (bfd *, const char *); + bfd_boolean (*_bfd_is_target_special_symbol) (bfd *, asymbol *); + alent * (*_get_lineno) (bfd *, struct bfd_symbol *); + bfd_boolean (*_bfd_find_nearest_line) + (bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, + const char **, const char **, unsigned int *); + bfd_boolean (*_bfd_find_line) + (bfd *, struct bfd_symbol **, struct bfd_symbol *, + const char **, unsigned int *); + bfd_boolean (*_bfd_find_inliner_info) + (bfd *, 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) + (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) + (bfd *, bfd_boolean, void **, 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) + (bfd *, bfd_boolean, const void *, asymbol *); + + /* Routines for relocs. */ +#define BFD_JUMP_TABLE_RELOCS(NAME) \ + NAME##_get_reloc_upper_bound, \ + NAME##_canonicalize_reloc, \ + NAME##_bfd_reloc_type_lookup + + long (*_get_reloc_upper_bound) (bfd *, sec_ptr); + long (*_bfd_canonicalize_reloc) + (bfd *, sec_ptr, arelent **, struct bfd_symbol **); + /* See documentation on reloc types. */ + reloc_howto_type * + (*reloc_type_lookup) (bfd *, bfd_reloc_code_real_type); + + /* Routines used when writing an object file. */ +#define BFD_JUMP_TABLE_WRITE(NAME) \ + NAME##_set_arch_mach, \ + NAME##_set_section_contents + + bfd_boolean (*_bfd_set_arch_mach) + (bfd *, enum bfd_architecture, unsigned long); + bfd_boolean (*_bfd_set_section_contents) + (bfd *, sec_ptr, const void *, file_ptr, bfd_size_type); + + /* Routines used by the linker. */ +#define BFD_JUMP_TABLE_LINK(NAME) \ + NAME##_sizeof_headers, \ + NAME##_bfd_get_relocated_section_contents, \ + NAME##_bfd_relax_section, \ + NAME##_bfd_link_hash_table_create, \ + NAME##_bfd_link_hash_table_free, \ + NAME##_bfd_link_add_symbols, \ + NAME##_bfd_link_just_syms, \ + NAME##_bfd_final_link, \ + NAME##_bfd_link_split_section, \ + NAME##_bfd_gc_sections, \ + NAME##_bfd_merge_sections, \ + NAME##_bfd_is_group_section, \ + NAME##_bfd_discard_group, \ + NAME##_section_already_linked \ + + int (*_bfd_sizeof_headers) (bfd *, bfd_boolean); + bfd_byte * (*_bfd_get_relocated_section_contents) + (bfd *, struct bfd_link_info *, struct bfd_link_order *, + bfd_byte *, bfd_boolean, struct bfd_symbol **); + + bfd_boolean (*_bfd_relax_section) + (bfd *, struct bfd_section *, 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) (bfd *); + + /* Release the memory associated with the linker hash table. */ + void (*_bfd_link_hash_table_free) (struct bfd_link_hash_table *); + + /* Add symbols from this object file into the hash table. */ + bfd_boolean (*_bfd_link_add_symbols) (bfd *, struct bfd_link_info *); + + /* Indicate that we are only retrieving symbol values from this section. */ + void (*_bfd_link_just_syms) (asection *, struct bfd_link_info *); + + /* Do a link based on the link_order structures attached to each + section of the BFD. */ + bfd_boolean (*_bfd_final_link) (bfd *, struct bfd_link_info *); + + /* Should this section be split up into smaller pieces during linking. */ + bfd_boolean (*_bfd_link_split_section) (bfd *, struct bfd_section *); + + /* Remove sections that are not referenced from the output. */ + bfd_boolean (*_bfd_gc_sections) (bfd *, struct bfd_link_info *); + + /* Attempt to merge SEC_MERGE sections. */ + bfd_boolean (*_bfd_merge_sections) (bfd *, struct bfd_link_info *); + + /* Is this section a member of a group? */ + bfd_boolean (*_bfd_is_group_section) (bfd *, const struct bfd_section *); + + /* Discard members of a group. */ + bfd_boolean (*_bfd_discard_group) (bfd *, struct bfd_section *); + + /* Check if SEC has been already linked during a reloceatable or + final link. */ + void (*_section_already_linked) (bfd *, struct bfd_section *); + + /* Routines to handle dynamic symbols and relocs. */ +#define BFD_JUMP_TABLE_DYNAMIC(NAME) \ + NAME##_get_dynamic_symtab_upper_bound, \ + NAME##_canonicalize_dynamic_symtab, \ + NAME##_get_synthetic_symtab, \ + NAME##_get_dynamic_reloc_upper_bound, \ + NAME##_canonicalize_dynamic_reloc + + /* Get the amount of memory required to hold the dynamic symbols. */ + long (*_bfd_get_dynamic_symtab_upper_bound) (bfd *); + /* Read in the dynamic symbols. */ + long (*_bfd_canonicalize_dynamic_symtab) + (bfd *, struct bfd_symbol **); + /* Create synthetized symbols. */ + long (*_bfd_get_synthetic_symtab) + (bfd *, long, struct bfd_symbol **, long, struct bfd_symbol **, + struct bfd_symbol **); + /* Get the amount of memory required to hold the dynamic relocs. */ + long (*_bfd_get_dynamic_reloc_upper_bound) (bfd *); + /* Read in the dynamic relocs. */ + long (*_bfd_canonicalize_dynamic_reloc) + (bfd *, arelent **, struct bfd_symbol **); + +@end example +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. +@example + /* 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. */ + const void *backend_data; + +@} bfd_target; + +@end example + +@findex bfd_set_default_target +@subsubsection @code{bfd_set_default_target} +@strong{Synopsis} +@example +bfd_boolean bfd_set_default_target (const char *name); +@end example +@strong{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. + +@findex bfd_find_target +@subsubsection @code{bfd_find_target} +@strong{Synopsis} +@example +const bfd_target *bfd_find_target (const char *target_name, bfd *abfd); +@end example +@strong{Description}@* +Return a pointer to the transfer vector for the object target +named @var{target_name}. If @var{target_name} is @code{NULL}, choose the +one in the environment variable @code{GNUTARGET}; 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 @code{bfd_check_format} to loop over all the +targets to find the one that matches the file being read. + +@findex bfd_target_list +@subsubsection @code{bfd_target_list} +@strong{Synopsis} +@example +const char ** bfd_target_list (void); +@end example +@strong{Description}@* +Return a freshly malloced NULL-terminated +vector of the names of all the valid BFD targets. Do not +modify the names. + +@findex bfd_seach_for_target +@subsubsection @code{bfd_seach_for_target} +@strong{Synopsis} +@example +const bfd_target *bfd_search_for_target + (int (*search_func) (const bfd_target *, void *), + void *); +@end example +@strong{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. + diff --git a/contrib/binutils-2.17/bfd/dwarf1.c b/contrib/binutils-2.17/bfd/dwarf1.c new file mode 100644 index 0000000000..5d6c1e359e --- /dev/null +++ b/contrib/binutils-2.17/bfd/dwarf1.c @@ -0,0 +1,556 @@ +/* DWARF 1 find nearest line (_bfd_dwarf1_find_nearest_line). + Copyright 1998, 1999, 2000, 2001, 2002, 2004, 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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. */ + +/* 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 (struct dwarf1_debug* stash) +{ + bfd_size_type amt = sizeof (struct dwarf1_unit); + + struct dwarf1_unit* x = 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 (struct dwarf1_debug* stash, struct dwarf1_unit* aUnit) +{ + bfd_size_type amt = sizeof (struct dwarf1_func); + + struct dwarf1_func* x = 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 (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 (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 = msec->rawsize ? msec->rawsize : msec->size; + stash->line_section = bfd_alloc (stash->abfd, size); + + if (! stash->line_section) + return FALSE; + + if (! bfd_get_section_contents (stash->abfd, msec, stash->line_section, + 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 = 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 (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 (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 (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 + = 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 = msec->rawsize ? msec->rawsize : msec->size; + stash->debug_section = bfd_alloc (abfd, size); + + if (! stash->debug_section) + return FALSE; + + if (! bfd_get_section_contents (abfd, msec, stash->debug_section, + 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; +} diff --git a/contrib/binutils-2.17/bfd/dwarf2.c b/contrib/binutils-2.17/bfd/dwarf2.c new file mode 100644 index 0000000000..ae68d18868 --- /dev/null +++ b/contrib/binutils-2.17/bfd/dwarf2.c @@ -0,0 +1,2798 @@ +/* DWARF 2 support. + Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2006 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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; + bfd_uint64_t val; + bfd_int64_t sval; + } + u; +}; + +/* Blocks are a bunch of untyped bytes. */ +struct dwarf_block +{ + unsigned int size; + bfd_byte *data; +}; + +struct loadable_section +{ + asection *section; + bfd_vma adj_vma; +}; + +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. */ + bfd_byte *info_ptr; + + /* Pointer to the end of the .debug_info section memory buffer. */ + bfd_byte *info_ptr_end; + + /* Pointer to the section and address of the beginning of the + section. */ + asection *sec; + bfd_byte *sec_info_ptr; + + /* Pointer to the symbol table. */ + asymbol **syms; + + /* Pointer to the .debug_abbrev section loaded into memory. */ + bfd_byte *dwarf_abbrev_buffer; + + /* Length of the loaded .debug_abbrev section. */ + unsigned long dwarf_abbrev_size; + + /* Buffer for decode_line_info. */ + bfd_byte *dwarf_line_buffer; + + /* Length of the loaded .debug_line section. */ + unsigned long dwarf_line_size; + + /* Pointer to the .debug_str section loaded into memory. */ + bfd_byte *dwarf_str_buffer; + + /* Length of the loaded .debug_str section. */ + unsigned long dwarf_str_size; + + /* Pointer to the .debug_ranges section loaded into memory. */ + bfd_byte *dwarf_ranges_buffer; + + /* Length of the loaded .debug_ranges section. */ + unsigned long dwarf_ranges_size; + + /* If the most recent call to bfd_find_nearest_line was given an + address in an inlined function, preserve a pointer into the + calling chain for subsequent calls to bfd_find_inliner_info to + use. */ + struct funcinfo *inliner_chain; + + /* Number of loadable sections. */ + unsigned int loadable_section_count; + + /* Array of loadable sections. */ + struct loadable_section *loadable_sections; +}; + +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 bfd convenient (for memory allocation). */ + bfd *abfd; + + /* The lowest and highest 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; + + /* Pointer to the current comp_unit so that we can find a given entry + by its reference. */ + bfd_byte *info_ptr_unit; + + /* The offset into .debug_line of the line number table. */ + unsigned long line_offset; + + /* Pointer to the first child die for the comp unit. */ + bfd_byte *first_child_die_ptr; + + /* The end of the comp unit. */ + bfd_byte *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; + + /* A list of the variables found in this comp. unit. */ + struct varinfo *variable_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; + + /* Base address for this unit - from DW_AT_low_pc attribute of + DW_TAG_compile_unit DIE */ + bfd_vma base_address; +}; + +/* 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 + +/* VERBATIM + The following function up to the END VERBATIM mark are + copied directly from dwarf2read.c. */ + +/* Read dwarf information from a buffer. */ + +static unsigned int +read_1_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf) +{ + return bfd_get_8 (abfd, buf); +} + +static int +read_1_signed_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf) +{ + return bfd_get_signed_8 (abfd, buf); +} + +static unsigned int +read_2_bytes (bfd *abfd, bfd_byte *buf) +{ + return bfd_get_16 (abfd, buf); +} + +static unsigned int +read_4_bytes (bfd *abfd, bfd_byte *buf) +{ + return bfd_get_32 (abfd, buf); +} + +static bfd_uint64_t +read_8_bytes (bfd *abfd, bfd_byte *buf) +{ + return bfd_get_64 (abfd, buf); +} + +static bfd_byte * +read_n_bytes (bfd *abfd ATTRIBUTE_UNUSED, + bfd_byte *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 (bfd *abfd ATTRIBUTE_UNUSED, + bfd_byte *buf, + unsigned int *bytes_read_ptr) +{ + /* Return a pointer to the embedded string. */ + char *str = (char *) buf; + if (*str == '\0') + { + *bytes_read_ptr = 1; + return NULL; + } + + *bytes_read_ptr = strlen (str) + 1; + return str; +} + +static char * +read_indirect_string (struct comp_unit* unit, + bfd_byte *buf, + unsigned int *bytes_read_ptr) +{ + bfd_uint64_t offset; + struct dwarf2_debug *stash = unit->stash; + char *str; + + 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; + bfd_size_type sz; + + 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; + } + + sz = msec->rawsize ? msec->rawsize : msec->size; + stash->dwarf_str_size = sz; + stash->dwarf_str_buffer = bfd_alloc (abfd, sz); + if (! stash->dwarf_str_buffer) + return NULL; + + if (! bfd_get_section_contents (abfd, msec, stash->dwarf_str_buffer, + 0, sz)) + 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; + } + + str = (char *) stash->dwarf_str_buffer + offset; + if (*str == '\0') + return NULL; + return str; +} + +/* END VERBATIM */ + +static bfd_uint64_t +read_address (struct comp_unit *unit, bfd_byte *buf) +{ + int signed_vma = get_elf_backend_data (unit->abfd)->sign_extend_vma; + + if (signed_vma) + { + switch (unit->addr_size) + { + case 8: + return bfd_get_signed_64 (unit->abfd, buf); + case 4: + return bfd_get_signed_32 (unit->abfd, buf); + case 2: + return bfd_get_signed_16 (unit->abfd, buf); + default: + abort (); + } + } + else + { + switch (unit->addr_size) + { + case 8: + return bfd_get_64 (unit->abfd, buf); + case 4: + return bfd_get_32 (unit->abfd, buf); + case 2: + return bfd_get_16 (unit->abfd, buf); + default: + abort (); + } + } +} + +/* Lookup an abbrev_info structure in the abbrev hash table. */ + +static struct abbrev_info * +lookup_abbrev (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 (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash) +{ + struct abbrev_info **abbrevs; + bfd_byte *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->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 = 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 = 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) + { + struct attr_abbrev *tmp; + + amt = cur_abbrev->num_attrs + ATTR_ALLOC_CHUNK; + amt *= sizeof (struct attr_abbrev); + tmp = bfd_realloc (cur_abbrev->attrs, amt); + if (tmp == NULL) + { + size_t i; + + for (i = 0; i < ABBREV_HASH_SIZE; i++) + { + struct abbrev_info *abbrev = abbrevs[i]; + + while (abbrev) + { + free (abbrev->attrs); + abbrev = abbrev->next; + } + } + return NULL; + } + cur_abbrev->attrs = tmp; + } + + 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 bfd_byte * +read_attribute_value (struct attribute *attr, + unsigned form, + struct comp_unit *unit, + bfd_byte *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: + attr->u.val = read_address (unit, info_ptr); + info_ptr += unit->addr_size; + break; + case DW_FORM_block2: + amt = sizeof (struct dwarf_block); + blk = 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; + attr->u.blk = blk; + break; + case DW_FORM_block4: + amt = sizeof (struct dwarf_block); + blk = 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; + attr->u.blk = blk; + break; + case DW_FORM_data2: + attr->u.val = read_2_bytes (abfd, info_ptr); + info_ptr += 2; + break; + case DW_FORM_data4: + attr->u.val = read_4_bytes (abfd, info_ptr); + info_ptr += 4; + break; + case DW_FORM_data8: + attr->u.val = read_8_bytes (abfd, info_ptr); + info_ptr += 8; + break; + case DW_FORM_string: + attr->u.str = read_string (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + break; + case DW_FORM_strp: + attr->u.str = read_indirect_string (unit, info_ptr, &bytes_read); + info_ptr += bytes_read; + break; + case DW_FORM_block: + amt = sizeof (struct dwarf_block); + blk = 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; + attr->u.blk = blk; + break; + case DW_FORM_block1: + amt = sizeof (struct dwarf_block); + blk = 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; + attr->u.blk = blk; + break; + case DW_FORM_data1: + attr->u.val = read_1_byte (abfd, info_ptr); + info_ptr += 1; + break; + case DW_FORM_flag: + attr->u.val = read_1_byte (abfd, info_ptr); + info_ptr += 1; + break; + case DW_FORM_sdata: + attr->u.sval = read_signed_leb128 (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + break; + case DW_FORM_udata: + attr->u.val = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + break; + case DW_FORM_ref1: + attr->u.val = read_1_byte (abfd, info_ptr); + info_ptr += 1; + break; + case DW_FORM_ref2: + attr->u.val = read_2_bytes (abfd, info_ptr); + info_ptr += 2; + break; + case DW_FORM_ref4: + attr->u.val = read_4_bytes (abfd, info_ptr); + info_ptr += 4; + break; + case DW_FORM_ref8: + attr->u.val = read_8_bytes (abfd, info_ptr); + info_ptr += 8; + break; + case DW_FORM_ref_udata: + attr->u.val = 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 bfd_byte * +read_attribute (struct attribute *attr, + struct attr_abbrev *abbrev, + struct comp_unit *unit, + bfd_byte *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' */ +}; + +/* Remember some information about each function. If the function is + inlined (DW_TAG_inlined_subroutine) it may have two additional + attributes, DW_AT_call_file and DW_AT_call_line, which specify the + source code location where this function was inlined. */ + +struct funcinfo +{ + struct funcinfo *prev_func; /* Pointer to previous function in list of all functions */ + struct funcinfo *caller_func; /* Pointer to function one scope higher */ + char *caller_file; /* Source location file name where caller_func inlines this func */ + int caller_line; /* Source location line number where caller_func inlines this func */ + char *file; /* Source location file name */ + int line; /* Source location line number */ + int tag; + char *name; + struct arange arange; + asection *sec; /* Where the symbol is defined */ +}; + +struct varinfo +{ + /* Pointer to previous variable in list of all variables */ + struct varinfo *prev_var; + /* Source location file name */ + char *file; + /* Source location line number */ + int line; + int tag; + char *name; + bfd_vma addr; + /* Where the symbol is defined */ + asection *sec; + /* Is this a stack variable? */ + unsigned int stack: 1; +}; + +/* Return TRUE if NEW_LINE should sort after LINE. */ + +static inline bfd_boolean +new_line_sorts_after (struct line_info *new_line, struct line_info *line) +{ + return (new_line->address > line->address + || (new_line->address == line->address + && new_line->end_sequence < line->end_sequence)); +} + + +/* 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 (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 = bfd_alloc (table->abfd, amt); + + /* Set member data of 'info'. */ + info->address = address; + info->line = line; + info->column = column; + info->end_sequence = end_sequence; + + if (filename && filename[0]) + { + info->filename = bfd_alloc (table->abfd, strlen (filename) + 1); + if (info->filename) + strcpy (info->filename, filename); + } + else + info->filename = NULL; + + /* 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'. */ + + if (!table->last_line + || new_line_sorts_after (info, table->last_line)) + { + /* 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; + } + else if (!new_line_sorts_after (info, table->lcl_head) + && (!table->lcl_head->prev_line + || new_line_sorts_after (info, table->lcl_head->prev_line))) + { + /* Abnormal but easy: lcl_head is the head of 'info'. */ + info->prev_line = table->lcl_head->prev_line; + table->lcl_head->prev_line = info; + } + else + { + /* Abnormal and hard: Neither 'last_line' nor 'lcl_head' are valid + heads for 'info'. Reset 'lcl_head'. */ + struct line_info* li2 = table->last_line; /* always non-NULL */ + struct line_info* li1 = li2->prev_line; + + while (li1) + { + if (!new_line_sorts_after (info, li2) + && new_line_sorts_after (info, li1)) + break; + + li2 = li1; /* always non-NULL */ + li1 = li1->prev_line; + } + table->lcl_head = li2; + info->prev_line = table->lcl_head->prev_line; + table->lcl_head->prev_line = info; + } +} + +/* 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 (struct line_info_table *table, unsigned int file) +{ + char *filename; + + if (file - 1 >= table->num_files) + { + /* FILE == 0 means unknown. */ + if (file) + (*_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 (bfd *abfd, struct arange *first_arange, bfd_vma low_pc, bfd_vma high_pc) +{ + struct arange *arange; + + /* If the first arange is empty, use it. */ + if (first_arange->high == 0) + { + first_arange->low = low_pc; + first_arange->high = high_pc; + return; + } + + /* Next see if we can cheaply extend an existing range. */ + arange = first_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); + + /* Need to allocate a new arange and insert it into the arange list. + Order isn't significant, so just insert after the first arange. */ + arange = bfd_zalloc (abfd, sizeof (*arange)); + arange->low = low_pc; + arange->high = high_pc; + arange->next = first_arange->next; + first_arange->next = arange; +} + +/* Decode the line number information for UNIT. */ + +static struct line_info_table* +decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) +{ + bfd *abfd = unit->abfd; + struct line_info_table* table; + bfd_byte *line_ptr; + bfd_byte *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->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 = 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 = 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) + { + char **tmp; + + amt = table->num_dirs + DIR_ALLOC_CHUNK; + amt *= sizeof (char *); + + tmp = bfd_realloc (table->dirs, amt); + if (tmp == NULL) + { + free (table->dirs); + return NULL; + } + table->dirs = tmp; + } + + 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) + { + struct fileinfo *tmp; + + amt = table->num_files + FILE_ALLOC_CHUNK; + amt *= sizeof (struct fileinfo); + + tmp = bfd_realloc (table->files, amt); + if (tmp == NULL) + { + free (table->files); + free (table->dirs); + return NULL; + } + table->files = tmp; + } + + 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 = table->num_files ? concat_filename (table, 1) : NULL; + 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 = (bfd_vma) -1; + 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 (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 (address < low_pc) + low_pc = address; + if (address > high_pc) + high_pc = address; + arange_add (unit->abfd, &unit->arange, 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) + { + struct fileinfo *tmp; + + amt = table->num_files + FILE_ALLOC_CHUNK; + amt *= sizeof (struct fileinfo); + tmp = bfd_realloc (table->files, amt); + if (tmp == NULL) + { + free (table->files); + free (table->dirs); + free (filename); + return NULL; + } + table->files = tmp; + } + 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); + free (filename); + free (table->files); + free (table->dirs); + return NULL; + } + break; + case DW_LNS_copy: + add_line_info (table, address, filename, line, column, 0); + basic_block = 0; + if (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 (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) + { + bfd_vma lowest_pc; + struct arange *arange; + + /* Find the lowest address in the function's range list */ + lowest_pc = function->arange.low; + for (arange = &function->arange; + arange; + arange = arange->next) + { + if (function->arange.low < lowest_pc) + lowest_pc = function->arange.low; + } + /* Check for spanning function and set outgoing line info */ + if (addr >= lowest_pc + && each_line->address < lowest_pc + && next_line->address > lowest_pc) + { + *filename_ptr = next_line->filename; + *linenumber_ptr = next_line->line; + } + else + { + *filename_ptr = each_line->filename; + *linenumber_ptr = each_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; +} + +/* Read in the .debug_ranges section for future reference */ + +static bfd_boolean +read_debug_ranges (struct comp_unit *unit) +{ + struct dwarf2_debug *stash = unit->stash; + if (! stash->dwarf_ranges_buffer) + { + bfd *abfd = unit->abfd; + asection *msec; + + msec = bfd_get_section_by_name (abfd, ".debug_ranges"); + if (! msec) + { + (*_bfd_error_handler) (_("Dwarf Error: Can't find .debug_ranges section.")); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + stash->dwarf_ranges_size = msec->size; + stash->dwarf_ranges_buffer + = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, + stash->syms); + if (! stash->dwarf_ranges_buffer) + return FALSE; + } + return TRUE; +} + +/* Function table functions. */ + +/* If ADDR is within TABLE, set FUNCTIONNAME_PTR, and return TRUE. + Note that we need to find the function that has the smallest + range that contains ADDR, to handle inlined functions without + depending upon them being ordered in TABLE by increasing range. */ + +static bfd_boolean +lookup_address_in_function_table (struct comp_unit *unit, + bfd_vma addr, + struct funcinfo **function_ptr, + const char **functionname_ptr) +{ + struct funcinfo* each_func; + struct funcinfo* best_fit = NULL; + struct arange *arange; + + for (each_func = unit->function_table; + each_func; + each_func = each_func->prev_func) + { + for (arange = &each_func->arange; + arange; + arange = arange->next) + { + if (addr >= arange->low && addr < arange->high) + { + if (!best_fit || + ((arange->high - arange->low) < (best_fit->arange.high - best_fit->arange.low))) + best_fit = each_func; + } + } + } + + if (best_fit) + { + *functionname_ptr = best_fit->name; + *function_ptr = best_fit; + return TRUE; + } + else + { + return FALSE; + } +} + +/* If SYM at ADDR is within function table of UNIT, set FILENAME_PTR + and LINENUMBER_PTR, and return TRUE. */ + +static bfd_boolean +lookup_symbol_in_function_table (struct comp_unit *unit, + asymbol *sym, + bfd_vma addr, + const char **filename_ptr, + unsigned int *linenumber_ptr) +{ + struct funcinfo* each_func; + struct funcinfo* best_fit = NULL; + struct arange *arange; + const char *name = bfd_asymbol_name (sym); + asection *sec = bfd_get_section (sym); + + for (each_func = unit->function_table; + each_func; + each_func = each_func->prev_func) + { + for (arange = &each_func->arange; + arange; + arange = arange->next) + { + if ((!each_func->sec || each_func->sec == sec) + && addr >= arange->low + && addr < arange->high + && each_func->name + && strcmp (name, each_func->name) == 0 + && (!best_fit + || ((arange->high - arange->low) + < (best_fit->arange.high - best_fit->arange.low)))) + best_fit = each_func; + } + } + + if (best_fit) + { + best_fit->sec = sec; + *filename_ptr = best_fit->file; + *linenumber_ptr = best_fit->line; + return TRUE; + } + else + return FALSE; +} + +/* Variable table functions. */ + +/* If SYM is within variable table of UNIT, set FILENAME_PTR and + LINENUMBER_PTR, and return TRUE. */ + +static bfd_boolean +lookup_symbol_in_variable_table (struct comp_unit *unit, + asymbol *sym, + bfd_vma addr, + const char **filename_ptr, + unsigned int *linenumber_ptr) +{ + const char *name = bfd_asymbol_name (sym); + asection *sec = bfd_get_section (sym); + struct varinfo* each; + + for (each = unit->variable_table; each; each = each->prev_var) + if (each->stack == 0 + && each->file != NULL + && each->name != NULL + && each->addr == addr + && (!each->sec || each->sec == sec) + && strcmp (name, each->name) == 0) + break; + + if (each) + { + each->sec = sec; + *filename_ptr = each->file; + *linenumber_ptr = each->line; + return TRUE; + } + else + return FALSE; +} + +static char * +find_abstract_instance_name (struct comp_unit *unit, bfd_uint64_t die_ref) +{ + bfd *abfd = unit->abfd; + bfd_byte *info_ptr; + unsigned int abbrev_number, bytes_read, i; + struct abbrev_info *abbrev; + struct attribute attr; + char *name = 0; + + info_ptr = unit->info_ptr_unit + die_ref; + abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + + if (abbrev_number) + { + 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); + } + else + { + for (i = 0; i < abbrev->num_attrs; ++i) + { + info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr); + switch (attr.name) + { + case DW_AT_name: + /* Prefer DW_AT_MIPS_linkage_name over DW_AT_name. */ + if (name == NULL) + name = attr.u.str; + break; + case DW_AT_specification: + name = find_abstract_instance_name (unit, attr.u.val); + break; + case DW_AT_MIPS_linkage_name: + name = attr.u.str; + break; + default: + break; + } + } + } + } + return (name); +} + +static void +read_rangelist (struct comp_unit *unit, struct arange *arange, bfd_uint64_t offset) +{ + bfd_byte *ranges_ptr; + bfd_vma base_address = unit->base_address; + + if (! unit->stash->dwarf_ranges_buffer) + { + if (! read_debug_ranges (unit)) + return; + } + ranges_ptr = unit->stash->dwarf_ranges_buffer + offset; + + for (;;) + { + bfd_vma low_pc; + bfd_vma high_pc; + + if (unit->addr_size == 4) + { + low_pc = read_4_bytes (unit->abfd, ranges_ptr); + ranges_ptr += 4; + high_pc = read_4_bytes (unit->abfd, ranges_ptr); + ranges_ptr += 4; + } + else + { + low_pc = read_8_bytes (unit->abfd, ranges_ptr); + ranges_ptr += 8; + high_pc = read_8_bytes (unit->abfd, ranges_ptr); + ranges_ptr += 8; + } + if (low_pc == 0 && high_pc == 0) + break; + if (low_pc == -1UL && high_pc != -1UL) + base_address = high_pc; + else + arange_add (unit->abfd, arange, base_address + low_pc, base_address + high_pc); + } +} + +/* DWARF2 Compilation unit functions. */ + +/* Scan over each die in a comp. unit looking for functions to add + to the function table and variables to the variable table. */ + +static bfd_boolean +scan_unit_for_symbols (struct comp_unit *unit) +{ + bfd *abfd = unit->abfd; + bfd_byte *info_ptr = unit->first_child_die_ptr; + int nesting_level = 1; + struct funcinfo **nested_funcs; + int nested_funcs_size; + + /* Maintain a stack of in-scope functions and inlined functions, which we + can use to set the caller_func field. */ + nested_funcs_size = 32; + nested_funcs = bfd_malloc (nested_funcs_size * sizeof (struct funcinfo *)); + if (nested_funcs == NULL) + return FALSE; + nested_funcs[nesting_level] = 0; + + while (nesting_level) + { + unsigned int abbrev_number, bytes_read, i; + struct abbrev_info *abbrev; + struct attribute attr; + struct funcinfo *func; + struct varinfo *var; + bfd_vma low_pc = 0; + bfd_vma high_pc = 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); + free (nested_funcs); + return FALSE; + } + + var = NULL; + if (abbrev->tag == DW_TAG_subprogram + || abbrev->tag == DW_TAG_entry_point + || abbrev->tag == DW_TAG_inlined_subroutine) + { + bfd_size_type amt = sizeof (struct funcinfo); + func = bfd_zalloc (abfd, amt); + func->tag = abbrev->tag; + func->prev_func = unit->function_table; + unit->function_table = func; + + if (func->tag == DW_TAG_inlined_subroutine) + for (i = nesting_level - 1; i >= 1; i--) + if (nested_funcs[i]) + { + func->caller_func = nested_funcs[i]; + break; + } + nested_funcs[nesting_level] = func; + } + else + { + func = NULL; + if (abbrev->tag == DW_TAG_variable) + { + bfd_size_type amt = sizeof (struct varinfo); + var = bfd_zalloc (abfd, amt); + var->tag = abbrev->tag; + var->stack = 1; + var->prev_var = unit->variable_table; + unit->variable_table = var; + } + + /* No inline function in scope at this nesting level. */ + nested_funcs[nesting_level] = 0; + } + + 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_call_file: + func->caller_file = concat_filename (unit->line_table, attr.u.val); + break; + + case DW_AT_call_line: + func->caller_line = attr.u.val; + break; + + case DW_AT_abstract_origin: + func->name = find_abstract_instance_name (unit, attr.u.val); + break; + + case DW_AT_name: + /* Prefer DW_AT_MIPS_linkage_name over DW_AT_name. */ + if (func->name == NULL) + func->name = attr.u.str; + break; + + case DW_AT_MIPS_linkage_name: + func->name = attr.u.str; + break; + + case DW_AT_low_pc: + low_pc = attr.u.val; + break; + + case DW_AT_high_pc: + high_pc = attr.u.val; + break; + + case DW_AT_ranges: + read_rangelist (unit, &func->arange, attr.u.val); + break; + + case DW_AT_decl_file: + func->file = concat_filename (unit->line_table, + attr.u.val); + break; + + case DW_AT_decl_line: + func->line = attr.u.val; + break; + + default: + break; + } + } + else if (var) + { + switch (attr.name) + { + case DW_AT_name: + var->name = attr.u.str; + break; + + case DW_AT_decl_file: + var->file = concat_filename (unit->line_table, + attr.u.val); + break; + + case DW_AT_decl_line: + var->line = attr.u.val; + break; + + case DW_AT_external: + if (attr.u.val != 0) + var->stack = 0; + break; + + case DW_AT_location: + switch (attr.form) + { + case DW_FORM_block: + case DW_FORM_block1: + case DW_FORM_block2: + case DW_FORM_block4: + if (*attr.u.blk->data == DW_OP_addr) + { + var->stack = 0; + + /* Verify that DW_OP_addr is the only opcode in the + location, in which case the block size will be 1 + plus the address size. */ + /* ??? For TLS variables, gcc can emit + DW_OP_addr DW_OP_GNU_push_tls_address + which we don't handle here yet. */ + if (attr.u.blk->size == unit->addr_size + 1U) + var->addr = bfd_get (unit->addr_size * 8, + unit->abfd, + attr.u.blk->data + 1); + } + break; + + default: + break; + } + break; + + default: + break; + } + } + } + + if (func && high_pc != 0) + { + arange_add (unit->abfd, &func->arange, low_pc, high_pc); + } + + if (abbrev->has_children) + { + nesting_level++; + + if (nesting_level >= nested_funcs_size) + { + struct funcinfo **tmp; + + nested_funcs_size *= 2; + tmp = bfd_realloc (nested_funcs, + (nested_funcs_size + * sizeof (struct funcinfo *))); + if (tmp == NULL) + { + free (nested_funcs); + return FALSE; + } + nested_funcs = tmp; + } + nested_funcs[nesting_level] = 0; + } + } + + free (nested_funcs); + 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 precedes 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 (bfd *abfd, + struct dwarf2_debug *stash, + bfd_vma unit_length, + bfd_byte *info_ptr_unit, + unsigned int offset_size) +{ + struct comp_unit* unit; + unsigned int version; + bfd_uint64_t 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; + bfd_byte *info_ptr = stash->info_ptr; + bfd_byte *end_ptr = info_ptr + unit_length; + bfd_size_type amt; + bfd_vma low_pc = 0; + bfd_vma high_pc = 0; + + 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 = 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; + unit->info_ptr_unit = info_ptr_unit; + + 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 = attr.u.val; + break; + + case DW_AT_name: + unit->name = attr.u.str; + break; + + case DW_AT_low_pc: + low_pc = attr.u.val; + /* If the compilation unit DIE has a DW_AT_low_pc attribute, + this is the base address to use when reading location + lists or range lists. */ + unit->base_address = low_pc; + break; + + case DW_AT_high_pc: + high_pc = attr.u.val; + break; + + case DW_AT_ranges: + read_rangelist (unit, &unit->arange, attr.u.val); + break; + + case DW_AT_comp_dir: + { + char *comp_dir = attr.u.str; + if (comp_dir) + { + /* Irix 6.2 native cc prepends .: to the compilation + directory, get rid of it. */ + char *cp = strchr (comp_dir, ':'); + + if (cp && cp != comp_dir && cp[-1] == '.' && cp[1] == '/') + comp_dir = cp + 1; + } + unit->comp_dir = comp_dir; + break; + } + + default: + break; + } + } + if (high_pc != 0) + { + arange_add (unit->abfd, &unit->arange, low_pc, high_pc); + } + + unit->first_child_die_ptr = info_ptr; + return unit; +} + +/* Return TRUE if UNIT may contain the address given by ADDR. When + there are functions written entirely with inline asm statements, the + range info in the compilation unit header may not be correct. We + need to consult the line info table to see if a compilation unit + really contains the given address. */ + +static bfd_boolean +comp_unit_contains_address (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 (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_symbols (unit)) + { + unit->error = 1; + return FALSE; + } + } + + function = NULL; + func_p = lookup_address_in_function_table (unit, addr, + &function, functionname_ptr); + if (func_p && (function->tag == DW_TAG_inlined_subroutine)) + stash->inliner_chain = function; + line_p = lookup_address_in_line_info_table (unit->line_table, addr, + function, filename_ptr, + linenumber_ptr); + return line_p || func_p; +} + +/* If UNIT contains SYM at ADDR, set the output parameters to the + values for the line containing SYM. The output parameters, + FILENAME_PTR, and LINENUMBER_PTR, are pointers to the objects to be + filled in. + + Return TRUE if UNIT contains SYM, and no errors were encountered; + FALSE otherwise. */ + +static bfd_boolean +comp_unit_find_line (struct comp_unit *unit, + asymbol *sym, + bfd_vma addr, + const char **filename_ptr, + unsigned int *linenumber_ptr, + struct dwarf2_debug *stash) +{ + 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_symbols (unit)) + { + unit->error = 1; + return FALSE; + } + } + + if (sym->flags & BSF_FUNCTION) + return lookup_symbol_in_function_table (unit, sym, addr, + filename_ptr, + linenumber_ptr); + else + return lookup_symbol_in_variable_table (unit, sym, addr, + filename_ptr, + linenumber_ptr); +} + +/* 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 (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; +} + +/* Unset vmas for loadable sections in STASH. */ + +static void +unset_sections (struct dwarf2_debug *stash) +{ + unsigned int i; + struct loadable_section *p; + + i = stash->loadable_section_count; + p = stash->loadable_sections; + for (; i > 0; i--, p++) + p->section->vma = 0; +} + +/* Set unique vmas for loadable sections in ABFD and save vmas in + STASH for unset_sections. */ + +static bfd_boolean +place_sections (bfd *abfd, struct dwarf2_debug *stash) +{ + struct loadable_section *p; + unsigned int i; + + if (stash->loadable_section_count != 0) + { + i = stash->loadable_section_count; + p = stash->loadable_sections; + for (; i > 0; i--, p++) + p->section->vma = p->adj_vma; + } + else + { + asection *sect; + bfd_vma last_vma = 0; + bfd_size_type amt; + struct loadable_section *p; + + i = 0; + for (sect = abfd->sections; sect != NULL; sect = sect->next) + { + bfd_size_type sz; + + if (sect->vma != 0 || (sect->flags & SEC_LOAD) == 0) + continue; + + sz = sect->rawsize ? sect->rawsize : sect->size; + if (sz == 0) + continue; + + i++; + } + + amt = i * sizeof (struct loadable_section); + p = (struct loadable_section *) bfd_zalloc (abfd, amt); + if (! p) + return FALSE; + + stash->loadable_sections = p; + stash->loadable_section_count = i; + + for (sect = abfd->sections; sect != NULL; sect = sect->next) + { + bfd_size_type sz; + + if (sect->vma != 0 || (sect->flags & SEC_LOAD) == 0) + continue; + + sz = sect->rawsize ? sect->rawsize : sect->size; + if (sz == 0) + continue; + + p->section = sect; + if (last_vma != 0) + { + /* Align the new address to the current section + alignment. */ + last_vma = ((last_vma + + ~((bfd_vma) -1 << sect->alignment_power)) + & ((bfd_vma) -1 << sect->alignment_power)); + sect->vma = last_vma; + } + p->adj_vma = sect->vma; + last_vma += sect->vma + sz; + + p++; + } + } + + return TRUE; +} + +/* 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 (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, + void **pinfo) +{ + /* Read each compilation unit from the section .debug_info, and check + to see if it contains the address we are searching for. If yes, + 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; + + /* What address are we looking for? */ + bfd_vma addr; + + struct comp_unit* each; + + bfd_vma found = FALSE; + + stash = *pinfo; + + if (! stash) + { + bfd_size_type amt = sizeof (struct dwarf2_debug); + + stash = bfd_zalloc (abfd, amt); + if (! stash) + return FALSE; + } + + /* In a relocatable file, 2 functions may have the same address. + We change the section vma so that they won't overlap. */ + if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) + { + if (! place_sections (abfd, stash)) + return FALSE; + } + + addr = offset; + if (section->output_section) + addr += section->output_section->vma + section->output_offset; + else + addr += section->vma; + *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 (! *pinfo) + { + bfd_size_type total_size; + asection *msec; + + *pinfo = 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. */ + goto done; + + /* 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->size; + + stash->info_ptr = bfd_alloc (abfd, total_size); + if (stash->info_ptr == NULL) + goto done; + + 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->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) + goto done; + + stash->inliner_chain = NULL; + + /* 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) + && comp_unit_find_nearest_line (each, addr, filename_ptr, + functionname_ptr, + linenumber_ptr, stash)) + { + found = TRUE; + goto done; + } + + /* Read each remaining comp. units checking each as they are read. */ + while (stash->info_ptr < stash->info_ptr_end) + { + bfd_vma length; + unsigned int offset_size = addr_size; + bfd_byte *info_ptr_unit = stash->info_ptr; + + 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, info_ptr_unit, + offset_size); + stash->info_ptr += length; + + if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr) + == stash->sec->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 + || comp_unit_contains_address (each, addr)) + && comp_unit_find_nearest_line (each, addr, + filename_ptr, + functionname_ptr, + linenumber_ptr, + stash)) + { + found = TRUE; + goto done; + } + } + } + } + +done: + if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) + unset_sections (stash); + + return found; +} + +/* The DWARF2 version of find_line. Return TRUE if the line is found + without error. */ + +bfd_boolean +_bfd_dwarf2_find_line (bfd *abfd, + asymbol **symbols, + asymbol *symbol, + const char **filename_ptr, + unsigned int *linenumber_ptr, + unsigned int addr_size, + void **pinfo) +{ + /* Read each compilation unit from the section .debug_info, and check + to see if it contains the address we are searching for. If yes, + 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; + + /* What address are we looking for? */ + bfd_vma addr; + + struct comp_unit* each; + + asection *section; + + bfd_boolean found = FALSE; + + section = bfd_get_section (symbol); + + stash = *pinfo; + + if (! stash) + { + bfd_size_type amt = sizeof (struct dwarf2_debug); + + stash = bfd_zalloc (abfd, amt); + if (! stash) + return FALSE; + } + + /* In a relocatable file, 2 functions may have the same address. + We change the section vma so that they won't overlap. */ + if (!stash && (abfd->flags & (EXEC_P | DYNAMIC)) == 0) + { + if (! place_sections (abfd, stash)) + return FALSE; + } + + addr = symbol->value; + if (section->output_section) + addr += section->output_section->vma + section->output_offset; + else + addr += section->vma; + + *filename_ptr = NULL; + *filename_ptr = NULL; + *linenumber_ptr = 0; + + if (! *pinfo) + { + bfd_size_type total_size; + asection *msec; + + *pinfo = 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. */ + goto done; + + /* 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->size; + + stash->info_ptr = bfd_alloc (abfd, total_size); + if (stash->info_ptr == NULL) + goto done; + + 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->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) + goto done; + + stash->inliner_chain = NULL; + + /* Check the previously read comp. units first. */ + for (each = stash->all_comp_units; each; each = each->next_unit) + if ((symbol->flags & BSF_FUNCTION) == 0 + || comp_unit_contains_address (each, addr)) + { + found = comp_unit_find_line (each, symbol, addr, filename_ptr, + linenumber_ptr, stash); + if (found) + goto done; + } + + /* 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); + + /* Read each remaining comp. units checking each as they are read. */ + while (stash->info_ptr < stash->info_ptr_end) + { + bfd_vma length; + unsigned int offset_size = addr_size; + bfd_byte *info_ptr_unit = stash->info_ptr; + + 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, info_ptr_unit, + offset_size); + stash->info_ptr += length; + + if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr) + == stash->sec->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. */ + found = (((symbol->flags & BSF_FUNCTION) == 0 + || each->arange.high <= 0 + || comp_unit_contains_address (each, addr)) + && comp_unit_find_line (each, symbol, addr, + filename_ptr, + linenumber_ptr, + stash)); + if (found) + goto done; + } + } + } + +done: + if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) + unset_sections (stash); + + return found; +} + +bfd_boolean +_bfd_dwarf2_find_inliner_info (bfd *abfd ATTRIBUTE_UNUSED, + const char **filename_ptr, + const char **functionname_ptr, + unsigned int *linenumber_ptr, + void **pinfo) +{ + struct dwarf2_debug *stash; + + stash = *pinfo; + if (stash) + { + struct funcinfo *func = stash->inliner_chain; + if (func && func->caller_func) + { + *filename_ptr = func->caller_file; + *functionname_ptr = func->caller_func->name; + *linenumber_ptr = func->caller_line; + stash->inliner_chain = func->caller_func; + return (TRUE); + } + } + + return (FALSE); +} + +void +_bfd_dwarf2_cleanup_debug_info (bfd *abfd) +{ + struct comp_unit *each; + struct dwarf2_debug *stash; + + if (abfd == NULL || elf_tdata (abfd) == NULL) + return; + + stash = elf_tdata (abfd)->dwarf2_find_line_info; + + if (stash == NULL) + return; + + for (each = stash->all_comp_units; each; each = each->next_unit) + { + struct abbrev_info **abbrevs = each->abbrevs; + size_t i; + + for (i = 0; i < ABBREV_HASH_SIZE; i++) + { + struct abbrev_info *abbrev = abbrevs[i]; + + while (abbrev) + { + free (abbrev->attrs); + abbrev = abbrev->next; + } + } + + if (each->line_table) + { + free (each->line_table->dirs); + free (each->line_table->files); + } + } + + free (stash->dwarf_abbrev_buffer); + free (stash->dwarf_line_buffer); + free (stash->dwarf_ranges_buffer); +} diff --git a/contrib/binutils-2.17/bfd/efi-app-ia32.c b/contrib/binutils-2.17/bfd/efi-app-ia32.c new file mode 100644 index 0000000000..b186f907ce --- /dev/null +++ b/contrib/binutils-2.17/bfd/efi-app-ia32.c @@ -0,0 +1,34 @@ +/* BFD back-end for Intel IA-32 EFI application files. + Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by David Mosberger + +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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "bfd.h" +#include "sysdep.h" + +#define TARGET_SYM bfd_efi_app_ia32_vec +#define TARGET_NAME "efi-app-ia32" +#define COFF_IMAGE_WITH_PE +#define COFF_WITH_PE +#define PCRELOFFSET TRUE +#define TARGET_UNDERSCORE '_' +#define COFF_LONG_SECTION_NAMES +#define PEI_TARGET_SUBSYSTEM IMAGE_SUBSYSTEM_EFI_APPLICATION +#define PEI_FORCE_MINIMUM_ALIGNMENT + +#include "coff-i386.c" diff --git a/contrib/binutils-2.17/bfd/efi-app-ia64.c b/contrib/binutils-2.17/bfd/efi-app-ia64.c new file mode 100644 index 0000000000..c2a77aca55 --- /dev/null +++ b/contrib/binutils-2.17/bfd/efi-app-ia64.c @@ -0,0 +1,35 @@ +/* BFD back-end for HP/Intel IA-64 EFI application files. + Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by David Mosberger + +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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "bfd.h" +#include "sysdep.h" + +#define TARGET_SYM bfd_efi_app_ia64_vec +#define TARGET_NAME "efi-app-ia64" +#define COFF_IMAGE_WITH_PE +#define COFF_WITH_PE +#define COFF_WITH_pep +#define PCRELOFFSET TRUE +#define TARGET_UNDERSCORE '_' +#define COFF_LONG_SECTION_NAMES +#define PEI_TARGET_SUBSYSTEM IMAGE_SUBSYSTEM_EFI_APPLICATION +#define PEI_FORCE_MINIMUM_ALIGNMENT + +#include "coff-ia64.c" diff --git a/contrib/binutils-2.17/bfd/elf-bfd.h b/contrib/binutils-2.17/bfd/elf-bfd.h new file mode 100644 index 0000000000..3fba1c228f --- /dev/null +++ b/contrib/binutils-2.17/bfd/elf-bfd.h @@ -0,0 +1,1955 @@ +/* BFD back-end data structures for ELF files. + Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2005, 2006 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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. */ +#ifndef NAME +#if ARCH_SIZE == 64 +#define NAME(x, y) x ## 64 ## _ ## y +#endif +#if ARCH_SIZE == 32 +#define NAME(x, y) x ## 32 ## _ ## y +#endif +#endif + +#ifndef NAME +#define NAME(x, y) 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; + void *mips_extr; + void *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; + + /* 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.). */ + unsigned int type : 8; + + /* Symbol st_other value, symbol visibility. */ + unsigned int other : 8; + + /* Symbol is referenced by a non-shared object. */ + unsigned int ref_regular : 1; + /* Symbol is defined by a non-shared object. */ + unsigned int def_regular : 1; + /* Symbol is referenced by a shared object. */ + unsigned int ref_dynamic : 1; + /* Symbol is defined by a shared object. */ + unsigned int def_dynamic : 1; + /* Symbol has a non-weak reference from a non-shared object. */ + unsigned int ref_regular_nonweak : 1; + /* Dynamic symbol has been adjustd. */ + unsigned int dynamic_adjusted : 1; + /* Symbol needs a copy reloc. */ + unsigned int needs_copy : 1; + /* Symbol needs a procedure linkage table entry. */ + unsigned int needs_plt : 1; + /* Symbol appears in a non-ELF input file. */ + unsigned int non_elf : 1; + /* Symbol should be marked as hidden in the version information. */ + unsigned int hidden : 1; + /* Symbol was forced to local scope due to a version script file. */ + unsigned int forced_local : 1; + /* Symbol was marked during garbage collection. */ + unsigned int mark : 1; + /* Symbol is referenced by a non-GOT/non-PLT relocation. This is + not currently set by all the backends. */ + unsigned int non_got_ref : 1; + /* Symbol has a definition in a shared object. + FIXME: There is no real need for this field if def_dynamic is never + cleared and all places that test def_dynamic also test def_regular. */ + unsigned int dynamic_def : 1; + /* Symbol is weak in all shared objects. */ + unsigned int dynamic_weak : 1; + /* Symbol is referenced with a relocation where C/C++ pointer equality + matters. */ + unsigned int pointer_equality_needed : 1; + + /* String table index in .dynstr if this is a dynamic symbol. */ + unsigned long dynstr_index; + + union + { + /* 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; + + /* Hash value of the name computed using the ELF hash function. + Used part way through size_dynamic_sections, after we've finished + with weakdefs. */ + unsigned long elf_hash_value; + } u; + + /* 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; + + struct + { + /* 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 size; + bfd_boolean *used; + + /* Virtual table derivation info. */ + struct elf_link_hash_entry *parent; + } *vtable; +}; + +/* Will references to this symbol always reference the symbol + in this object? STV_PROTECTED is excluded from the visibility test + here so that function pointer comparisons work properly. Since + function symbols not defined in an app are set to their .plt entry, + it's necessary for shared libs to also reference the .plt even + though the symbol is really local to the shared lib. */ +#define SYMBOL_REFERENCES_LOCAL(INFO, H) \ + _bfd_elf_symbol_refs_local_p (H, INFO, 0) + +/* Will _calls_ to this symbol always call the version in this object? */ +#define SYMBOL_CALLS_LOCAL(INFO, H) \ + _bfd_elf_symbol_refs_local_p (H, INFO, 1) + +/* Common symbols that are turned into definitions don't have the + DEF_REGULAR flag set, so they might appear to be undefined. */ +#define ELF_COMMON_DEF_P(H) \ + (!(H)->def_regular \ + && !(H)->def_dynamic \ + && (H)->root.type == bfd_link_hash_defined) + +/* 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; + char augmentation[20]; + bfd_vma code_align; + bfd_signed_vma data_align; + bfd_vma ra_column; + bfd_vma 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 +{ + /* For FDEs, this points to the CIE used. */ + struct eh_cie_fde *cie_inf; + unsigned int size; + unsigned int offset; + unsigned int new_offset; + unsigned char fde_encoding; + unsigned char lsda_encoding; + unsigned char lsda_offset; + unsigned int cie : 1; + unsigned int removed : 1; + unsigned int add_augmentation_size : 1; + unsigned int add_fde_encoding : 1; + unsigned int make_relative : 1; + unsigned int make_lsda_relative : 1; + unsigned int need_lsda_relative : 1; + unsigned int 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; + struct eh_cie_fde *last_cie_inf; + asection *hdr_sec; + 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; + bfd_boolean offsets_adjusted; +}; + +/* 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_got_offset/init_plt_offset + in size_dynamic_sections when the values may be offsets. */ + union gotplt_union init_got_refcount; + union gotplt_union init_plt_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_got_offset; + union gotplt_union init_plt_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; + + /* The _PROCEDURE_LINKAGE_TABLE_ symbol. */ + struct elf_link_hash_entry *hplt; + + /* A pointer to information used to merge SEC_MERGE sections. */ + void *merge_info; + + /* Used to link stabs in sections. */ + struct stab_info stab_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 first output tls section and size of PT_TLS segment. */ + asection *tls_sec; + bfd_size_type tls_size; + + /* A linked list of BFD's loaded in the link. */ + struct elf_link_loaded_list *loaded; + + /* True if this target has relocatable executables, so needs dynamic + section symbols. */ + bfd_boolean is_relocatable_executable; +}; + +/* 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 (*) (struct bfd_link_hash_entry *, void *)) (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(htab) \ + (((struct bfd_link_hash_table *) (htab))->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, log_file_align; + unsigned char elfclass, ev_current; + int (*write_out_phdrs) + (bfd *, const Elf_Internal_Phdr *, unsigned int); + bfd_boolean + (*write_shdrs_and_ehdr) (bfd *); + void (*write_relocs) + (bfd *, asection *, void *); + void (*swap_symbol_in) + (bfd *, const void *, const void *, Elf_Internal_Sym *); + void (*swap_symbol_out) + (bfd *, const Elf_Internal_Sym *, void *, void *); + bfd_boolean (*slurp_reloc_table) + (bfd *, asection *, asymbol **, bfd_boolean); + long (*slurp_symbol_table) + (bfd *, asymbol **, bfd_boolean); + void (*swap_dyn_in) + (bfd *, const void *, Elf_Internal_Dyn *); + void (*swap_dyn_out) + (bfd *, const Elf_Internal_Dyn *, void *); + + /* 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) + (bfd *, const bfd_byte *, Elf_Internal_Rela *); + + /* This function is called to swap out a REL relocation. */ + void (*swap_reloc_out) + (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) + (bfd *, const bfd_byte *, Elf_Internal_Rela *); + + /* This function is called to swap out a RELA relocation. */ + void (*swap_reloca_out) + (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; + int r_sym_shift; + bfd_boolean bad_symtab; +}; + +/* The level of IRIX compatibility we're striving for. */ + +typedef enum { + ict_none, + ict_irix5, + ict_irix6 +} irix_compat_t; + +/* Mapping of ELF section names and types. */ +struct bfd_elf_special_section +{ + const char *prefix; + int prefix_length; + /* 0 means name must match PREFIX exactly. + -1 means name must start with PREFIX followed by an arbitrary string. + -2 means name must match PREFIX exactly or consist of PREFIX followed + by a dot then anything. + > 0 means name must start with the first PREFIX_LENGTH chars of + PREFIX and finish with the last SUFFIX_LENGTH chars of PREFIX. */ + int suffix_length; + int type; + int attr; +}; + +enum action_discarded + { + COMPLAIN = 1, + PRETEND = 2 + }; + +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; + + /* The minimum page size for this backend. An input object will not be + considered page aligned unless its sections are correctly aligned for + pages at least this large. May be smaller than maxpagesize. */ + bfd_vma minpagesize; + + /* The BFD flags applied to sections created for dynamic linking. */ + flagword dynamic_sec_flags; + + /* A function to translate an ELF RELA relocation to a BFD arelent + structure. */ + void (*elf_info_to_howto) + (bfd *, arelent *, Elf_Internal_Rela *); + + /* A function to translate an ELF REL relocation to a BFD arelent + structure. */ + void (*elf_info_to_howto_rel) + (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) + (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) + (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) + (bfd *, asymbol *); + + /* A function to do additional symbol processing after reading the + entire ELF symbol table. */ + bfd_boolean (*elf_backend_symbol_table_processing) + (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) + (Elf_Internal_Sym *, int); + + /* A function to return the linker hash table entry of a symbol that + might be satisfied by an archive symbol. */ + struct elf_link_hash_entry * (*elf_backend_archive_symbol_lookup) + (bfd *, struct bfd_link_info *, const char *); + + /* Return true if local section symbols should have a non-null st_name. + NULL implies false. */ + bfd_boolean (*elf_backend_name_local_section_symbols) + (bfd *); + + /* 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) + (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) + (bfd *, Elf_Internal_Shdr *, const char *, int); + + /* A function to convert machine dependent ELF section header flags to + BFD internal section header flags. */ + bfd_boolean (*elf_backend_section_flags) + (flagword *, const Elf_Internal_Shdr *); + + /* A function that returns a struct containing ELF section flags and + type for the given BFD section. */ + const struct bfd_elf_special_section * (*get_sec_type_attr) + (bfd *, asection *); + + /* A function to handle unusual program segment types when creating BFD + sections from ELF program segments. */ + bfd_boolean (*elf_backend_section_from_phdr) + (bfd *, Elf_Internal_Phdr *, int, const char *); + + /* 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) + (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) + (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) + (bfd *abfd, struct bfd_link_info *info, 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) + (struct bfd_link_info *info, const char *, Elf_Internal_Sym *, + asection *, struct elf_link_hash_entry *); + + /* 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) + (bfd *abfd, struct bfd_link_info *info); + + /* When creating a shared library, determine whether to omit the + dynamic symbol for the section. */ + bfd_boolean (*elf_backend_omit_section_dynsym) + (bfd *output_bfd, struct bfd_link_info *info, asection *osec); + + /* 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) + (bfd *abfd, struct bfd_link_info *info, asection *o, + const Elf_Internal_Rela *relocs); + + /* The CHECK_DIRECTIVES function is called once per input file by + the add_symbols phase of the ELF backend linker. The function + must inspect the bfd and create any additional symbols according + to any custom directives in the bfd. */ + bfd_boolean (*check_directives) + (bfd *abfd, struct bfd_link_info *info); + + /* 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) + (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) + (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) + (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 + relocatable output file) adjusting the reloc addend as + necessary. + + This function does not have to worry about setting the reloc + address or the reloc symbol index. + + LOCAL_SYMS is a pointer to the swapped in local symbols. + + LOCAL_SECTIONS is an array giving the section in the input file + corresponding to the st_shndx field of each local symbol. + + The global hash table entry for the global symbols can be found + via elf_sym_hashes (input_bfd). + + When generating relocatable output, this function must handle + STB_LOCAL/STT_SECTION symbols specially. The output symbol is + going to be the section symbol corresponding to the output + section, which means that the addend must be adjusted + accordingly. */ + bfd_boolean (*elf_backend_relocate_section) + (bfd *output_bfd, struct bfd_link_info *info, bfd *input_bfd, + asection *input_section, bfd_byte *contents, Elf_Internal_Rela *relocs, + Elf_Internal_Sym *local_syms, asection **local_sections); + + /* 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) + (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) + (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) + (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) + (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) + (bfd *); + + /* This function is called to modify an existing segment map in a + backend specific fashion. */ + bfd_boolean (*elf_backend_modify_segment_map) + (bfd *, struct bfd_link_info *); + + /* This function is called during section garbage collection to + mark sections that define global symbols. */ + bfd_boolean (*gc_mark_dynamic_ref) + (struct elf_link_hash_entry *h, void *inf); + + /* This function is called during section gc to discover the section a + particular relocation refers to. */ + asection * (*gc_mark_hook) + (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) + (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) + (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) + (bfd *, void *, asymbol *); + + /* This function, if defined, is called after all local symbols and + global symbols converted to locals are emitted 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) + (bfd *, struct bfd_link_info *, void *, + bfd_boolean (*) (void *, const char *, Elf_Internal_Sym *, asection *, + struct elf_link_hash_entry *)); + + /* 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) + (struct bfd_link_info *, 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) + (struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean); + + /* A function to do additional symbol fixup, called by + _bfd_elf_fix_symbol_flags. */ + bfd_boolean (*elf_backend_fixup_symbol) + (struct bfd_link_info *, struct elf_link_hash_entry *); + + /* Merge the backend specific symbol attribute. */ + void (*elf_backend_merge_symbol_attribute) + (struct elf_link_hash_entry *, const Elf_Internal_Sym *, bfd_boolean, + bfd_boolean); + + /* Decide whether an undefined symbol is special and can be ignored. + This is the case for OPTIONAL symbols on IRIX. */ + bfd_boolean (*elf_backend_ignore_undef_symbol) + (struct elf_link_hash_entry *); + + /* 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) + (bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *, + struct elf_link_hash_entry **); + + /* Count relocations. Not called for relocatable links + or if all relocs are being preserved in the output. */ + unsigned int (*elf_backend_count_relocs) + (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) + (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) + (bfd *, Elf_Internal_Note *); + + /* Functions to print VMAs. Special code to handle 64 bit ELF files. */ + void (* elf_backend_sprintf_vma) + (bfd *, char *, bfd_vma); + void (* elf_backend_fprintf_vma) + (bfd *, void *, bfd_vma); + + /* This function returns class of a reloc type. */ + enum elf_reloc_type_class (*elf_backend_reloc_type_class) + (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) + (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) + (asection *); + + /* What to do when ld finds relocations against symbols defined in + discarded sections. */ + unsigned int (*action_discarded) + (asection *); + + /* This function returns the width of FDE pointers in bytes, or 0 if + that can't be determined for some reason. The default definition + goes by the bfd's EI_CLASS. */ + unsigned int (*elf_backend_eh_frame_address_size) + (bfd *, asection *); + + /* These functions tell elf-eh-frame whether to attempt to turn + absolute or lsda encodings into pc-relative ones. The default + definition enables these transformations. */ + bfd_boolean (*elf_backend_can_make_relative_eh_frame) + (bfd *, struct bfd_link_info *, asection *); + bfd_boolean (*elf_backend_can_make_lsda_relative_eh_frame) + (bfd *, struct bfd_link_info *, asection *); + + /* This function returns an encoding after computing the encoded + value (and storing it in ENCODED) for the given OFFSET into OSEC, + to be stored in at LOC_OFFSET into the LOC_SEC input section. + The default definition chooses a 32-bit PC-relative encoding. */ + bfd_byte (*elf_backend_encode_eh_address) + (bfd *abfd, struct bfd_link_info *info, + asection *osec, bfd_vma offset, + asection *loc_sec, bfd_vma loc_offset, + bfd_vma *encoded); + + /* 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) + (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) + (bfd *); + + reloc_howto_type *(*elf_backend_mips_rtype_to_howto) + (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; + + /* This function implements `bfd_elf_bfd_from_remote_memory'; + see elf.c, elfcode.h. */ + bfd *(*elf_backend_bfd_from_remote_memory) + (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, + int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, int len)); + + /* This function is used by `_bfd_elf_get_synthetic_symtab'; + see elf.c. */ + bfd_vma (*plt_sym_val) (bfd_vma, const asection *, const arelent *); + + /* Is symbol defined in common section? */ + bfd_boolean (*common_definition) (Elf_Internal_Sym *); + + /* Return a common section index for section. */ + unsigned int (*common_section_index) (asection *); + + /* Return a common section for section. */ + asection *(*common_section) (asection *); + + /* Return TRUE if we can merge 2 definitions. */ + bfd_boolean (*merge_symbol) (struct bfd_link_info *, + struct elf_link_hash_entry **, + struct elf_link_hash_entry *, + Elf_Internal_Sym *, asection **, + bfd_vma *, unsigned int *, + bfd_boolean *, bfd_boolean *, + bfd_boolean *, bfd_boolean *, + bfd_boolean *, bfd_boolean *, + bfd_boolean *, bfd_boolean *, + bfd *, asection **, + bfd_boolean *, bfd_boolean *, + bfd_boolean *, bfd_boolean *, + bfd *, asection **); + + /* Used to handle bad SHF_LINK_ORDER input. */ + bfd_error_handler_type link_order_error_handler; + + /* Name of the PLT relocation section. */ + const char *relplt_name; + + /* Alternate EM_xxxx machine codes for this backend. */ + int elf_machine_alt1; + int elf_machine_alt2; + + const struct elf_size_info *s; + + /* An array of target specific special sections. */ + const struct bfd_elf_special_section *special_sections; + + /* The size in bytes of the header for the GOT. This includes the + so-called reserved entries on some systems. */ + bfd_vma got_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. */ + 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; + + /* A pointer to the linked-to section for SHF_LINK_ORDER. */ + asection *linked_to; + + /* 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. */ + void *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 bfd_symbol *id; + } group; + + /* Optional information about section group; NULL if it doesn't + belongs to any section group. */ + asection *sec_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. */ + void *sec_info; +}; + +#define elf_section_data(sec) ((struct bfd_elf_section_data*)(sec)->used_by_bfd) +#define elf_linked_to_section(sec) (elf_section_data(sec)->linked_to) +#define elf_section_type(sec) (elf_section_data(sec)->this_hdr.sh_type) +#define elf_section_flags(sec) (elf_section_data(sec)->this_hdr.sh_flags) +#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) +#define elf_sec_group(sec) (elf_section_data(sec)->sec_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) \ + ((const struct elf_backend_data *) (abfd)->xvec->backend_data) + +/* 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; +}; + +/* This structure is used to pass information to + _bfd_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 + _bfd_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; +}; + +/* 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; + bfd_vma gp; /* The gp value */ + unsigned int gp_size; /* The gp size */ + + /* Information grabbed from an elf core file. */ + int core_signal; + int core_pid; + int core_lwpid; + char* core_program; + char* core_command; + + /* 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; + + /* 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; + + /* Records the result of `get_program_header_size'. */ + bfd_size_type program_header_size; + + /* Used by find_nearest_line entry point. */ + void *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. */ + void *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; + + Elf_Internal_Shdr **group_sect_ptr; + int num_group; + + /* 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; + + /* Segment flags for the PT_GNU_STACK segment. */ + unsigned int stack_flags; + + /* Should the PT_GNU_RELRO segment be emitted? */ + bfd_boolean relro; + + /* Symbol version definitions in external objects. */ + Elf_Internal_Verdef *verdef; + + /* Symbol version references to external objects. */ + Elf_Internal_Verneed *verref; + + /* 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; + + /* Whether a dyanmic object was specified normally on the linker + command line, or was specified when --as-needed was in effect, + or was found via a DT_NEEDED entry. */ + enum dynamic_lib_link_class dyn_lib_class; + + /* This is set to TRUE if the object was created by the backend + linker. */ + bfd_boolean linker; + + /* 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; + + /* Used to determine if the e_flags field has been initialized */ + bfd_boolean flags_init; +}; + +#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_dt_name(bfd) (elf_tdata(bfd) -> dt_name) +#define elf_dyn_lib_class(bfd) (elf_tdata(bfd) -> dyn_lib_class) +#define elf_bad_symtab(bfd) (elf_tdata(bfd) -> bad_symtab) +#define elf_flags_init(bfd) (elf_tdata(bfd) -> flags_init) + +extern void _bfd_elf_swap_verdef_in + (bfd *, const Elf_External_Verdef *, Elf_Internal_Verdef *); +extern void _bfd_elf_swap_verdef_out + (bfd *, const Elf_Internal_Verdef *, Elf_External_Verdef *); +extern void _bfd_elf_swap_verdaux_in + (bfd *, const Elf_External_Verdaux *, Elf_Internal_Verdaux *); +extern void _bfd_elf_swap_verdaux_out + (bfd *, const Elf_Internal_Verdaux *, Elf_External_Verdaux *); +extern void _bfd_elf_swap_verneed_in + (bfd *, const Elf_External_Verneed *, Elf_Internal_Verneed *); +extern void _bfd_elf_swap_verneed_out + (bfd *, const Elf_Internal_Verneed *, Elf_External_Verneed *); +extern void _bfd_elf_swap_vernaux_in + (bfd *, const Elf_External_Vernaux *, Elf_Internal_Vernaux *); +extern void _bfd_elf_swap_vernaux_out + (bfd *, const Elf_Internal_Vernaux *, Elf_External_Vernaux *); +extern void _bfd_elf_swap_versym_in + (bfd *, const Elf_External_Versym *, Elf_Internal_Versym *); +extern void _bfd_elf_swap_versym_out + (bfd *, const Elf_Internal_Versym *, Elf_External_Versym *); + +extern int _bfd_elf_section_from_bfd_section + (bfd *, asection *); +extern char *bfd_elf_string_from_elf_section + (bfd *, unsigned, unsigned); +extern char *bfd_elf_get_str_section + (bfd *, unsigned); +extern Elf_Internal_Sym *bfd_elf_get_elf_syms + (bfd *, Elf_Internal_Shdr *, size_t, size_t, Elf_Internal_Sym *, void *, + Elf_External_Sym_Shndx *); +extern const char *bfd_elf_sym_name + (bfd *, Elf_Internal_Shdr *, Elf_Internal_Sym *, asection *); + +extern bfd_boolean _bfd_elf_copy_private_bfd_data + (bfd *, bfd *); +extern bfd_boolean _bfd_elf_print_private_bfd_data + (bfd *, void *); +extern void bfd_elf_print_symbol + (bfd *, void *, asymbol *, bfd_print_symbol_type); + +extern void _bfd_elf_sprintf_vma + (bfd *, char *, bfd_vma); +extern void _bfd_elf_fprintf_vma + (bfd *, void *, bfd_vma); + +extern unsigned int _bfd_elf_eh_frame_address_size + (bfd *, asection *); +extern bfd_byte _bfd_elf_encode_eh_address + (bfd *abfd, struct bfd_link_info *info, asection *osec, bfd_vma offset, + asection *loc_sec, bfd_vma loc_offset, bfd_vma *encoded); +extern bfd_boolean _bfd_elf_can_make_relative + (bfd *input_bfd, struct bfd_link_info *info, asection *eh_frame_section); + +extern enum elf_reloc_type_class _bfd_elf_reloc_type_class + (const Elf_Internal_Rela *); +extern bfd_vma _bfd_elf_rela_local_sym + (bfd *, Elf_Internal_Sym *, asection **, Elf_Internal_Rela *); +extern bfd_vma _bfd_elf_rel_local_sym + (bfd *, Elf_Internal_Sym *, asection **, bfd_vma); +extern bfd_vma _bfd_elf_section_offset + (bfd *, struct bfd_link_info *, asection *, bfd_vma); + +extern unsigned long bfd_elf_hash + (const char *); + +extern bfd_reloc_status_type bfd_elf_generic_reloc + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); +extern bfd_boolean bfd_elf_mkobject + (bfd *); +extern bfd_boolean bfd_elf_mkcorefile + (bfd *); +extern Elf_Internal_Shdr *bfd_elf_find_section + (bfd *, char *); +extern bfd_boolean _bfd_elf_make_section_from_shdr + (bfd *, Elf_Internal_Shdr *, const char *, int); +extern bfd_boolean _bfd_elf_make_section_from_phdr + (bfd *, Elf_Internal_Phdr *, int, const char *); +extern struct bfd_hash_entry *_bfd_elf_link_hash_newfunc + (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); +extern struct bfd_link_hash_table *_bfd_elf_link_hash_table_create + (bfd *); +extern void _bfd_elf_link_hash_copy_indirect + (struct bfd_link_info *, struct elf_link_hash_entry *, + struct elf_link_hash_entry *); +extern void _bfd_elf_link_hash_hide_symbol + (struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean); +extern bfd_boolean _bfd_elf_link_hash_fixup_symbol + (struct bfd_link_info *, struct elf_link_hash_entry *); +extern bfd_boolean _bfd_elf_link_hash_table_init + (struct elf_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) + (struct bfd_hash_entry *, struct bfd_hash_table *, const char *), + unsigned int); +extern bfd_boolean _bfd_elf_slurp_version_tables + (bfd *, bfd_boolean); +extern bfd_boolean _bfd_elf_merge_sections + (bfd *, struct bfd_link_info *); +extern bfd_boolean _bfd_elf_match_sections_by_type + (bfd *, const asection *, bfd *, const asection *); +extern bfd_boolean bfd_elf_is_group_section + (bfd *, const struct bfd_section *); +extern void _bfd_elf_section_already_linked + (bfd *, struct bfd_section *); +extern void bfd_elf_set_group_contents + (bfd *, asection *, void *); +extern asection *_bfd_elf_check_kept_section + (asection *); +extern void _bfd_elf_link_just_syms + (asection *, struct bfd_link_info *); +extern bfd_boolean _bfd_elf_copy_private_header_data + (bfd *, bfd *); +extern bfd_boolean _bfd_elf_copy_private_symbol_data + (bfd *, asymbol *, bfd *, asymbol *); +#define _bfd_generic_init_private_section_data \ + _bfd_elf_init_private_section_data +extern bfd_boolean _bfd_elf_init_private_section_data + (bfd *, asection *, bfd *, asection *, struct bfd_link_info *); +extern bfd_boolean _bfd_elf_copy_private_section_data + (bfd *, asection *, bfd *, asection *); +extern bfd_boolean _bfd_elf_write_object_contents + (bfd *); +extern bfd_boolean _bfd_elf_write_corefile_contents + (bfd *); +extern bfd_boolean _bfd_elf_set_section_contents + (bfd *, sec_ptr, const void *, file_ptr, bfd_size_type); +extern long _bfd_elf_get_symtab_upper_bound + (bfd *); +extern long _bfd_elf_canonicalize_symtab + (bfd *, asymbol **); +extern long _bfd_elf_get_dynamic_symtab_upper_bound + (bfd *); +extern long _bfd_elf_canonicalize_dynamic_symtab + (bfd *, asymbol **); +extern long _bfd_elf_get_synthetic_symtab + (bfd *, long, asymbol **, long, asymbol **, asymbol **); +extern long _bfd_elf_get_reloc_upper_bound + (bfd *, sec_ptr); +extern long _bfd_elf_canonicalize_reloc + (bfd *, sec_ptr, arelent **, asymbol **); +extern long _bfd_elf_get_dynamic_reloc_upper_bound + (bfd *); +extern long _bfd_elf_canonicalize_dynamic_reloc + (bfd *, arelent **, asymbol **); +extern asymbol *_bfd_elf_make_empty_symbol + (bfd *); +extern void _bfd_elf_get_symbol_info + (bfd *, asymbol *, symbol_info *); +extern bfd_boolean _bfd_elf_is_local_label_name + (bfd *, const char *); +extern alent *_bfd_elf_get_lineno + (bfd *, asymbol *); +extern bfd_boolean _bfd_elf_set_arch_mach + (bfd *, enum bfd_architecture, unsigned long); +extern bfd_boolean _bfd_elf_find_nearest_line + (bfd *, asection *, asymbol **, bfd_vma, const char **, const char **, + unsigned int *); +extern bfd_boolean _bfd_elf_find_line + (bfd *, asymbol **, asymbol *, const char **, unsigned int *); +#define _bfd_generic_find_line _bfd_elf_find_line +extern bfd_boolean _bfd_elf_find_inliner_info + (bfd *, 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 + (bfd *, bfd_boolean); +extern bfd_boolean _bfd_elf_new_section_hook + (bfd *, asection *); +extern bfd_boolean _bfd_elf_init_reloc_shdr + (bfd *, Elf_Internal_Shdr *, asection *, bfd_boolean); +extern const struct bfd_elf_special_section *_bfd_elf_get_special_section + (const char *, const struct bfd_elf_special_section *, unsigned int); +extern const struct bfd_elf_special_section *_bfd_elf_get_sec_type_attr + (bfd *, asection *); + +/* If the target doesn't have reloc handling written yet: */ +extern void _bfd_elf_no_info_to_howto + (bfd *, arelent *, Elf_Internal_Rela *); + +extern bfd_boolean bfd_section_from_shdr + (bfd *, unsigned int shindex); +extern bfd_boolean bfd_section_from_phdr + (bfd *, Elf_Internal_Phdr *, int); + +extern int _bfd_elf_symbol_from_bfd_symbol + (bfd *, asymbol **); + +extern asection *bfd_section_from_r_symndx + (bfd *, struct sym_sec_cache *, asection *, unsigned long); +extern asection *bfd_section_from_elf_index + (bfd *, unsigned int); +extern struct bfd_strtab_hash *_bfd_elf_stringtab_init + (void); + +extern struct elf_strtab_hash * _bfd_elf_strtab_init + (void); +extern void _bfd_elf_strtab_free + (struct elf_strtab_hash *); +extern bfd_size_type _bfd_elf_strtab_add + (struct elf_strtab_hash *, const char *, bfd_boolean); +extern void _bfd_elf_strtab_addref + (struct elf_strtab_hash *, bfd_size_type); +extern void _bfd_elf_strtab_delref + (struct elf_strtab_hash *, bfd_size_type); +extern void _bfd_elf_strtab_clear_all_refs + (struct elf_strtab_hash *); +extern bfd_size_type _bfd_elf_strtab_size + (struct elf_strtab_hash *); +extern bfd_size_type _bfd_elf_strtab_offset + (struct elf_strtab_hash *, bfd_size_type); +extern bfd_boolean _bfd_elf_strtab_emit + (bfd *, struct elf_strtab_hash *); +extern void _bfd_elf_strtab_finalize + (struct elf_strtab_hash *); + +extern bfd_boolean _bfd_elf_discard_section_eh_frame + (bfd *, struct bfd_link_info *, asection *, + bfd_boolean (*) (bfd_vma, void *), struct elf_reloc_cookie *); +extern bfd_boolean _bfd_elf_discard_section_eh_frame_hdr + (bfd *, struct bfd_link_info *); +extern bfd_vma _bfd_elf_eh_frame_section_offset + (bfd *, struct bfd_link_info *, asection *, bfd_vma); +extern bfd_boolean _bfd_elf_write_section_eh_frame + (bfd *, struct bfd_link_info *, asection *, bfd_byte *); +extern bfd_boolean _bfd_elf_write_section_eh_frame_hdr + (bfd *, struct bfd_link_info *); +extern bfd_boolean _bfd_elf_maybe_strip_eh_frame_hdr + (struct bfd_link_info *); + +extern bfd_boolean _bfd_elf_merge_symbol + (bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *, + asection **, bfd_vma *, unsigned int *, + struct elf_link_hash_entry **, bfd_boolean *, + bfd_boolean *, bfd_boolean *, bfd_boolean *); + +extern bfd_boolean _bfd_elf_add_default_symbol + (bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, + const char *, Elf_Internal_Sym *, asection **, bfd_vma *, + bfd_boolean *, bfd_boolean); + +extern bfd_boolean _bfd_elf_export_symbol + (struct elf_link_hash_entry *, void *); + +extern bfd_boolean _bfd_elf_link_find_version_dependencies + (struct elf_link_hash_entry *, void *); + +extern bfd_boolean _bfd_elf_link_assign_sym_version + (struct elf_link_hash_entry *, void *); + +extern long _bfd_elf_link_lookup_local_dynindx + (struct bfd_link_info *, bfd *, long); +extern bfd_boolean _bfd_elf_compute_section_file_positions + (bfd *, struct bfd_link_info *); +extern void _bfd_elf_assign_file_positions_for_relocs + (bfd *); +extern file_ptr _bfd_elf_assign_file_position_for_section + (Elf_Internal_Shdr *, file_ptr, bfd_boolean); + +extern bfd_boolean _bfd_elf_validate_reloc + (bfd *, arelent *); + +extern bfd_boolean _bfd_elf_link_create_dynamic_sections + (bfd *, struct bfd_link_info *); +extern bfd_boolean _bfd_elf_link_omit_section_dynsym + (bfd *, struct bfd_link_info *, asection *); +extern bfd_boolean _bfd_elf_create_dynamic_sections + (bfd *, struct bfd_link_info *); +extern bfd_boolean _bfd_elf_create_got_section + (bfd *, struct bfd_link_info *); +extern struct elf_link_hash_entry *_bfd_elf_define_linkage_sym + (bfd *, struct bfd_link_info *, asection *, const char *); + +extern bfd_boolean _bfd_elfcore_make_pseudosection + (bfd *, char *, size_t, ufile_ptr); +extern char *_bfd_elfcore_strndup + (bfd *, char *, size_t); + +extern Elf_Internal_Rela *_bfd_elf_link_read_relocs + (bfd *, asection *, void *, Elf_Internal_Rela *, bfd_boolean); + +extern bfd_boolean _bfd_elf_link_size_reloc_section + (bfd *, Elf_Internal_Shdr *, asection *); + +extern bfd_boolean _bfd_elf_link_output_relocs + (bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *, + struct elf_link_hash_entry **); + +extern bfd_boolean _bfd_elf_fix_symbol_flags + (struct elf_link_hash_entry *, struct elf_info_failed *); + +extern bfd_boolean _bfd_elf_adjust_dynamic_symbol + (struct elf_link_hash_entry *, void *); + +extern bfd_boolean _bfd_elf_link_sec_merge_syms + (struct elf_link_hash_entry *, void *); + +extern bfd_boolean _bfd_elf_dynamic_symbol_p + (struct elf_link_hash_entry *, struct bfd_link_info *, bfd_boolean); + +extern bfd_boolean _bfd_elf_symbol_refs_local_p + (struct elf_link_hash_entry *, struct bfd_link_info *, bfd_boolean); + +extern bfd_boolean bfd_elf_match_symbols_in_sections + (asection *sec1, asection *sec2); + +extern bfd_boolean _bfd_elf_setup_sections + (bfd *); + +extern const bfd_target *bfd_elf32_object_p + (bfd *); +extern const bfd_target *bfd_elf32_core_file_p + (bfd *); +extern char *bfd_elf32_core_file_failing_command + (bfd *); +extern int bfd_elf32_core_file_failing_signal + (bfd *); +extern bfd_boolean bfd_elf32_core_file_matches_executable_p + (bfd *, bfd *); + +extern void bfd_elf32_swap_symbol_in + (bfd *, const void *, const void *, Elf_Internal_Sym *); +extern void bfd_elf32_swap_symbol_out + (bfd *, const Elf_Internal_Sym *, void *, void *); +extern void bfd_elf32_swap_reloc_in + (bfd *, const bfd_byte *, Elf_Internal_Rela *); +extern void bfd_elf32_swap_reloc_out + (bfd *, const Elf_Internal_Rela *, bfd_byte *); +extern void bfd_elf32_swap_reloca_in + (bfd *, const bfd_byte *, Elf_Internal_Rela *); +extern void bfd_elf32_swap_reloca_out + (bfd *, const Elf_Internal_Rela *, bfd_byte *); +extern void bfd_elf32_swap_phdr_in + (bfd *, const Elf32_External_Phdr *, Elf_Internal_Phdr *); +extern void bfd_elf32_swap_phdr_out + (bfd *, const Elf_Internal_Phdr *, Elf32_External_Phdr *); +extern void bfd_elf32_swap_dyn_in + (bfd *, const void *, Elf_Internal_Dyn *); +extern void bfd_elf32_swap_dyn_out + (bfd *, const Elf_Internal_Dyn *, void *); +extern long bfd_elf32_slurp_symbol_table + (bfd *, asymbol **, bfd_boolean); +extern bfd_boolean bfd_elf32_write_shdrs_and_ehdr + (bfd *); +extern int bfd_elf32_write_out_phdrs + (bfd *, const Elf_Internal_Phdr *, unsigned int); +extern void bfd_elf32_write_relocs + (bfd *, asection *, void *); +extern bfd_boolean bfd_elf32_slurp_reloc_table + (bfd *, asection *, asymbol **, bfd_boolean); + +extern const bfd_target *bfd_elf64_object_p + (bfd *); +extern const bfd_target *bfd_elf64_core_file_p + (bfd *); +extern char *bfd_elf64_core_file_failing_command + (bfd *); +extern int bfd_elf64_core_file_failing_signal + (bfd *); +extern bfd_boolean bfd_elf64_core_file_matches_executable_p + (bfd *, bfd *); + +extern void bfd_elf64_swap_symbol_in + (bfd *, const void *, const void *, Elf_Internal_Sym *); +extern void bfd_elf64_swap_symbol_out + (bfd *, const Elf_Internal_Sym *, void *, void *); +extern void bfd_elf64_swap_reloc_in + (bfd *, const bfd_byte *, Elf_Internal_Rela *); +extern void bfd_elf64_swap_reloc_out + (bfd *, const Elf_Internal_Rela *, bfd_byte *); +extern void bfd_elf64_swap_reloca_in + (bfd *, const bfd_byte *, Elf_Internal_Rela *); +extern void bfd_elf64_swap_reloca_out + (bfd *, const Elf_Internal_Rela *, bfd_byte *); +extern void bfd_elf64_swap_phdr_in + (bfd *, const Elf64_External_Phdr *, Elf_Internal_Phdr *); +extern void bfd_elf64_swap_phdr_out + (bfd *, const Elf_Internal_Phdr *, Elf64_External_Phdr *); +extern void bfd_elf64_swap_dyn_in + (bfd *, const void *, Elf_Internal_Dyn *); +extern void bfd_elf64_swap_dyn_out + (bfd *, const Elf_Internal_Dyn *, void *); +extern long bfd_elf64_slurp_symbol_table + (bfd *, asymbol **, bfd_boolean); +extern bfd_boolean bfd_elf64_write_shdrs_and_ehdr + (bfd *); +extern int bfd_elf64_write_out_phdrs + (bfd *, const Elf_Internal_Phdr *, unsigned int); +extern void bfd_elf64_write_relocs + (bfd *, asection *, void *); +extern bfd_boolean bfd_elf64_slurp_reloc_table + (bfd *, asection *, asymbol **, bfd_boolean); + +extern struct elf_link_hash_entry *_bfd_elf_archive_symbol_lookup + (bfd *, struct bfd_link_info *, const char *); +extern bfd_boolean bfd_elf_link_add_symbols + (bfd *, struct bfd_link_info *); +extern bfd_boolean _bfd_elf_add_dynamic_entry + (struct bfd_link_info *, bfd_vma, bfd_vma); + +extern bfd_boolean bfd_elf_link_record_dynamic_symbol + (struct bfd_link_info *, struct elf_link_hash_entry *); + +extern int bfd_elf_link_record_local_dynamic_symbol + (struct bfd_link_info *, bfd *, long); + +extern bfd_boolean _bfd_elf_close_and_cleanup + (bfd *); + +extern bfd_boolean _bfd_elf_common_definition + (Elf_Internal_Sym *); + +extern unsigned int _bfd_elf_common_section_index + (asection *); + +extern asection *_bfd_elf_common_section + (asection *); + +extern void _bfd_dwarf2_cleanup_debug_info + (bfd *); + +extern bfd_reloc_status_type _bfd_elf_rel_vtable_reloc_fn + (bfd *, arelent *, struct bfd_symbol *, void *, + asection *, bfd *, char **); + +extern bfd_boolean bfd_elf_final_link + (bfd *, struct bfd_link_info *); + +extern bfd_boolean bfd_elf_gc_mark_dynamic_ref_symbol + (struct elf_link_hash_entry *h, void *inf); + +extern bfd_boolean bfd_elf_gc_sections + (bfd *, struct bfd_link_info *); + +extern bfd_boolean bfd_elf_gc_record_vtinherit + (bfd *, asection *, struct elf_link_hash_entry *, bfd_vma); + +extern bfd_boolean bfd_elf_gc_record_vtentry + (bfd *, asection *, struct elf_link_hash_entry *, bfd_vma); + +extern bfd_boolean _bfd_elf_gc_mark + (struct bfd_link_info *, asection *, + asection * (*) (asection *, struct bfd_link_info *, Elf_Internal_Rela *, + struct elf_link_hash_entry *, Elf_Internal_Sym *)); + +extern bfd_boolean bfd_elf_gc_common_finalize_got_offsets + (bfd *, struct bfd_link_info *); + +extern bfd_boolean bfd_elf_gc_common_final_link + (bfd *, struct bfd_link_info *); + +extern bfd_boolean bfd_elf_reloc_symbol_deleted_p + (bfd_vma, void *); + +extern struct elf_segment_map * +_bfd_elf_make_dynamic_segment + (bfd *, asection *); + +/* Exported interface for writing elf corefile notes. */ +extern char *elfcore_write_note + (bfd *, char *, int *, const char *, int, const void *, int); +extern char *elfcore_write_prpsinfo + (bfd *, char *, int *, const char *, const char *); +extern char *elfcore_write_prstatus + (bfd *, char *, int *, long, int, const void *); +extern char * elfcore_write_pstatus + (bfd *, char *, int *, long, int, const void *); +extern char *elfcore_write_prfpreg + (bfd *, char *, int *, const void *, int); +extern char *elfcore_write_prxfpreg + (bfd *, char *, int *, const void *, int); +extern char *elfcore_write_lwpstatus + (bfd *, char *, int *, long, int, const void *); + +extern bfd *_bfd_elf32_bfd_from_remote_memory + (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, + int (*target_read_memory) (bfd_vma, bfd_byte *, int)); +extern bfd *_bfd_elf64_bfd_from_remote_memory + (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, + int (*target_read_memory) (bfd_vma, bfd_byte *, int)); + +/* Large common section. */ +extern asection _bfd_elf_large_com_section; + +/* SH ELF specific routine. */ + +extern bfd_boolean _sh_elf_set_mach_from_flags + (bfd *); + +/* This is the condition under which finish_dynamic_symbol will be called. + If our finish_dynamic_symbol isn't called, we'll need to do something + about initializing any .plt and .got entries in relocate_section. */ +#define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, SHARED, H) \ + ((DYN) \ + && ((SHARED) || !(H)->forced_local) \ + && ((H)->dynindx != -1 || (H)->forced_local)) + +/* This macro is to avoid lots of duplicated code in the body + of xxx_relocate_section() in the various elfxx-xxxx.c files. */ +#define RELOC_FOR_GLOBAL_SYMBOL(info, input_bfd, input_section, rel, \ + r_symndx, symtab_hdr, sym_hashes, \ + h, sec, relocation, \ + unresolved_reloc, warned) \ + do \ + { \ + /* It seems this can happen with erroneous or unsupported \ + input (mixing a.out and elf in an archive, for example.) */ \ + if (sym_hashes == NULL) \ + return FALSE; \ + \ + 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; \ + \ + warned = FALSE; \ + unresolved_reloc = FALSE; \ + 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 == NULL \ + || 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->unresolved_syms_in_objects == RM_IGNORE \ + && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) \ + ; \ + else \ + { \ + bfd_boolean err; \ + err = (info->unresolved_syms_in_objects == RM_GENERATE_ERROR \ + || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT); \ + if (!info->callbacks->undefined_symbol (info, \ + h->root.root.string, \ + input_bfd, \ + input_section, \ + rel->r_offset, err)) \ + return FALSE; \ + warned = TRUE; \ + } \ + } \ + while (0) + +#endif /* _LIBELF_H_ */ diff --git a/contrib/binutils-2.17/bfd/elf-eh-frame.c b/contrib/binutils-2.17/bfd/elf-eh-frame.c new file mode 100644 index 0000000000..5100e72938 --- /dev/null +++ b/contrib/binutils-2.17/bfd/elf-eh-frame.c @@ -0,0 +1,1424 @@ +/* .eh_frame section optimization. + Copyright 2001, 2002, 2003, 2004, 2005, 2006 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf/dwarf2.h" + +#define EH_FRAME_HDR_SIZE 8 + +/* If *ITER hasn't reached END yet, read the next byte into *RESULT and + move onto the next byte. Return true on success. */ + +static inline bfd_boolean +read_byte (bfd_byte **iter, bfd_byte *end, unsigned char *result) +{ + if (*iter >= end) + return FALSE; + *result = *((*iter)++); + return TRUE; +} + +/* Move *ITER over LENGTH bytes, or up to END, whichever is closer. + Return true it was possible to move LENGTH bytes. */ + +static inline bfd_boolean +skip_bytes (bfd_byte **iter, bfd_byte *end, bfd_size_type length) +{ + if ((bfd_size_type) (end - *iter) < length) + { + *iter = end; + return FALSE; + } + *iter += length; + return TRUE; +} + +/* Move *ITER over an leb128, stopping at END. Return true if the end + of the leb128 was found. */ + +static bfd_boolean +skip_leb128 (bfd_byte **iter, bfd_byte *end) +{ + unsigned char byte; + do + if (!read_byte (iter, end, &byte)) + return FALSE; + while (byte & 0x80); + return TRUE; +} + +/* Like skip_leb128, but treat the leb128 as an unsigned value and + store it in *VALUE. */ + +static bfd_boolean +read_uleb128 (bfd_byte **iter, bfd_byte *end, bfd_vma *value) +{ + bfd_byte *start, *p; + + start = *iter; + if (!skip_leb128 (iter, end)) + return FALSE; + + p = *iter; + *value = *--p; + while (p > start) + *value = (*value << 7) | (*--p & 0x7f); + + return TRUE; +} + +/* Like read_uleb128, but for signed values. */ + +static bfd_boolean +read_sleb128 (bfd_byte **iter, bfd_byte *end, bfd_signed_vma *value) +{ + bfd_byte *start, *p; + + start = *iter; + if (!skip_leb128 (iter, end)) + return FALSE; + + p = *iter; + *value = ((*--p & 0x7f) ^ 0x40) - 0x40; + while (p > start) + *value = (*value << 7) | (*--p & 0x7f); + + return TRUE; +} + +/* Return 0 if either encoding is variable width, or not yet known to bfd. */ + +static +int get_DW_EH_PE_width (int encoding, int 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 (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 (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 (struct cie *c1, struct cie *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; +} + +/* Return the number of extra bytes that we'll be inserting into + ENTRY's augmentation string. */ + +static INLINE unsigned int +extra_augmentation_string_bytes (struct eh_cie_fde *entry) +{ + unsigned int size = 0; + if (entry->cie) + { + if (entry->add_augmentation_size) + size++; + if (entry->add_fde_encoding) + size++; + } + return size; +} + +/* Likewise ENTRY's augmentation data. */ + +static INLINE unsigned int +extra_augmentation_data_bytes (struct eh_cie_fde *entry) +{ + unsigned int size = 0; + if (entry->cie) + { + if (entry->add_augmentation_size) + size++; + if (entry->add_fde_encoding) + size++; + } + else + { + if (entry->cie_inf->add_augmentation_size) + size++; + } + return size; +} + +/* Return the size that ENTRY will have in the output. ALIGNMENT is the + required alignment of ENTRY in bytes. */ + +static unsigned int +size_of_output_cie_fde (struct eh_cie_fde *entry, unsigned int alignment) +{ + if (entry->removed) + return 0; + if (entry->size == 4) + return 4; + return (entry->size + + extra_augmentation_string_bytes (entry) + + extra_augmentation_data_bytes (entry) + + alignment - 1) & -alignment; +} + +/* Assume that the bytes between *ITER and END are CFA instructions. + Try to move *ITER past the first instruction and return true on + success. ENCODED_PTR_WIDTH gives the width of pointer entries. */ + +static bfd_boolean +skip_cfa_op (bfd_byte **iter, bfd_byte *end, unsigned int encoded_ptr_width) +{ + bfd_byte op; + bfd_vma length; + + if (!read_byte (iter, end, &op)) + return FALSE; + + switch (op & 0x80 ? op & 0xc0 : op) + { + case DW_CFA_nop: + case DW_CFA_advance_loc: + case DW_CFA_restore: + /* No arguments. */ + return TRUE; + + case DW_CFA_offset: + case DW_CFA_restore_extended: + case DW_CFA_undefined: + case DW_CFA_same_value: + case DW_CFA_def_cfa_register: + case DW_CFA_def_cfa_offset: + case DW_CFA_def_cfa_offset_sf: + case DW_CFA_GNU_args_size: + /* One leb128 argument. */ + return skip_leb128 (iter, end); + + case DW_CFA_offset_extended: + case DW_CFA_register: + case DW_CFA_def_cfa: + case DW_CFA_offset_extended_sf: + case DW_CFA_GNU_negative_offset_extended: + case DW_CFA_def_cfa_sf: + /* Two leb128 arguments. */ + return (skip_leb128 (iter, end) + && skip_leb128 (iter, end)); + + case DW_CFA_def_cfa_expression: + /* A variable-length argument. */ + return (read_uleb128 (iter, end, &length) + && skip_bytes (iter, end, length)); + + case DW_CFA_expression: + /* A leb128 followed by a variable-length argument. */ + return (skip_leb128 (iter, end) + && read_uleb128 (iter, end, &length) + && skip_bytes (iter, end, length)); + + case DW_CFA_set_loc: + return skip_bytes (iter, end, encoded_ptr_width); + + case DW_CFA_advance_loc1: + return skip_bytes (iter, end, 1); + + case DW_CFA_advance_loc2: + return skip_bytes (iter, end, 2); + + case DW_CFA_advance_loc4: + return skip_bytes (iter, end, 4); + + case DW_CFA_MIPS_advance_loc8: + return skip_bytes (iter, end, 8); + + default: + return FALSE; + } +} + +/* Try to interpret the bytes between BUF and END as CFA instructions. + If every byte makes sense, return a pointer to the first DW_CFA_nop + padding byte, or END if there is no padding. Return null otherwise. + ENCODED_PTR_WIDTH is as for skip_cfa_op. */ + +static bfd_byte * +skip_non_nops (bfd_byte *buf, bfd_byte *end, unsigned int encoded_ptr_width) +{ + bfd_byte *last; + + last = buf; + while (buf < end) + if (*buf == DW_CFA_nop) + buf++; + else + { + if (!skip_cfa_op (&buf, end, encoded_ptr_width)) + return 0; + last = buf; + } + return last; +} + +/* 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 + (bfd *abfd, struct bfd_link_info *info, asection *sec, + bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *), + struct elf_reloc_cookie *cookie) +{ +#define REQUIRE(COND) \ + do \ + if (!(COND)) \ + goto free_no_table; \ + while (0) + + bfd_byte *ehbuf = NULL, *buf; + bfd_byte *last_cie, *last_fde; + struct eh_cie_fde *ent, *last_cie_inf, *this_inf; + 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 cie_usage_count, offset; + unsigned int ptr_size; + + if (sec->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. */ + + REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf)); + + if (sec->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). */ + REQUIRE (sec->size == (unsigned int) sec->size); + + ptr_size = (get_elf_backend_data (abfd) + ->elf_backend_eh_frame_address_size (abfd, sec)); + REQUIRE (ptr_size != 0); + + buf = ehbuf; + last_cie = NULL; + last_cie_inf = NULL; + memset (&cie, 0, sizeof (cie)); + cie_usage_count = 0; + sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) + + 99 * sizeof (struct eh_cie_fde)); + REQUIRE (sec_info); + + sec_info->alloced = 100; + +#define ENSURE_NO_RELOCS(buf) \ + REQUIRE (!(cookie->rel < cookie->relend \ + && (cookie->rel->r_offset \ + < (bfd_size_type) ((buf) - ehbuf)) \ + && cookie->rel->r_info != 0)) + +#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 (;;) + { + char *aug; + bfd_byte *start, *end, *insns; + bfd_size_type length; + + if (sec_info->count == sec_info->alloced) + { + struct eh_cie_fde *old_entry = sec_info->entry; + sec_info = bfd_realloc (sec_info, + sizeof (struct eh_frame_sec_info) + + ((sec_info->alloced + 99) + * sizeof (struct eh_cie_fde))); + REQUIRE (sec_info); + + memset (&sec_info->entry[sec_info->alloced], 0, + 100 * sizeof (struct eh_cie_fde)); + sec_info->alloced += 100; + + /* Now fix any pointers into the array. */ + if (last_cie_inf >= old_entry + && last_cie_inf < old_entry + sec_info->count) + last_cie_inf = sec_info->entry + (last_cie_inf - old_entry); + } + + this_inf = sec_info->entry + sec_info->count; + 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->size) + { + hdr.length = 0; + hdr.id = (unsigned int) -1; + end = buf; + } + else + { + /* Read the length of the entry. */ + REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4)); + hdr.length = bfd_get_32 (abfd, buf - 4); + + /* 64-bit .eh_frame is not supported. */ + REQUIRE (hdr.length != 0xffffffff); + + /* The CIE/FDE must be fully contained in this input section. */ + REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr.length <= sec->size); + end = buf + hdr.length; + + this_inf->offset = last_fde - ehbuf; + this_inf->size = 4 + hdr.length; + + if (hdr.length == 0) + { + /* A zero-length CIE should only be found at the end of + the section. */ + REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size); + ENSURE_NO_RELOCS (buf); + sec_info->count++; + /* Now just finish last encountered CIE processing and break + the loop. */ + hdr.id = (unsigned int) -1; + } + else + { + REQUIRE (skip_bytes (&buf, end, 4)); + hdr.id = bfd_get_32 (abfd, buf - 4); + REQUIRE (hdr.id != (unsigned int) -1); + } + } + + 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->relocatable + && hdr_info->last_cie_sec + && (sec->output_section + == hdr_info->last_cie_sec->output_section) + && cie_compare (&cie, &hdr_info->last_cie) == 0) + || cie_usage_count == 0) + last_cie_inf->removed = 1; + else + { + hdr_info->last_cie = cie; + hdr_info->last_cie_sec = sec; + last_cie_inf->make_relative = cie.make_relative; + last_cie_inf->make_lsda_relative = cie.make_lsda_relative; + last_cie_inf->per_encoding_relative + = (cie.per_encoding & 0x70) == DW_EH_PE_pcrel; + } + } + + if (hdr.id == (unsigned int) -1) + break; + + last_cie_inf = this_inf; + this_inf->cie = 1; + + cie_usage_count = 0; + memset (&cie, 0, sizeof (cie)); + cie.hdr = hdr; + REQUIRE (read_byte (&buf, end, &cie.version)); + + /* Cannot handle unknown versions. */ + REQUIRE (cie.version == 1 || cie.version == 3); + REQUIRE (strlen ((char *) buf) < sizeof (cie.augmentation)); + + strcpy (cie.augmentation, (char *) buf); + buf = (bfd_byte *) strchr ((char *) 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. */ + REQUIRE (skip_bytes (&buf, end, ptr_size)); + SKIP_RELOCS (buf); + } + REQUIRE (read_uleb128 (&buf, end, &cie.code_align)); + REQUIRE (read_sleb128 (&buf, end, &cie.data_align)); + if (cie.version == 1) + { + REQUIRE (buf < end); + cie.ra_column = *buf++; + } + else + REQUIRE (read_uleb128 (&buf, end, &cie.ra_column)); + 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++; + REQUIRE (read_uleb128 (&buf, end, &cie.augmentation_size)); + ENSURE_NO_RELOCS (buf); + } + + while (*aug != '\0') + switch (*aug++) + { + case 'L': + REQUIRE (read_byte (&buf, end, &cie.lsda_encoding)); + ENSURE_NO_RELOCS (buf); + REQUIRE (get_DW_EH_PE_width (cie.lsda_encoding, ptr_size)); + break; + case 'R': + REQUIRE (read_byte (&buf, end, &cie.fde_encoding)); + ENSURE_NO_RELOCS (buf); + REQUIRE (get_DW_EH_PE_width (cie.fde_encoding, ptr_size)); + break; + case 'S': + break; + case 'P': + { + int per_width; + + REQUIRE (read_byte (&buf, end, &cie.per_encoding)); + per_width = get_DW_EH_PE_width (cie.per_encoding, + ptr_size); + REQUIRE (per_width); + if ((cie.per_encoding & 0xf0) == DW_EH_PE_aligned) + { + length = -(buf - ehbuf) & (per_width - 1); + REQUIRE (skip_bytes (&buf, end, length)); + } + 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; + } + /* Cope with MIPS-style composite relocations. */ + do + cookie->rel++; + while (GET_RELOC (buf) != NULL); + } + REQUIRE (skip_bytes (&buf, end, 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 + && (get_elf_backend_data (abfd) + ->elf_backend_can_make_relative_eh_frame + (abfd, info, sec))) + { + if ((cie.fde_encoding & 0xf0) == DW_EH_PE_absptr) + cie.make_relative = 1; + /* If the CIE doesn't already have an 'R' entry, it's fairly + easy to add one, provided that there's no aligned data + after the augmentation string. */ + else if (cie.fde_encoding == DW_EH_PE_omit + && (cie.per_encoding & 0xf0) != DW_EH_PE_aligned) + { + if (*cie.augmentation == 0) + this_inf->add_augmentation_size = 1; + this_inf->add_fde_encoding = 1; + cie.make_relative = 1; + } + } + + if (info->shared + && (get_elf_backend_data (abfd) + ->elf_backend_can_make_lsda_relative_eh_frame + (abfd, info, sec)) + && (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 = end - buf; + if (initial_insn_length <= 50) + { + cie.initial_insn_length = initial_insn_length; + memcpy (cie.initial_instructions, buf, initial_insn_length); + } + insns = buf; + buf += initial_insn_length; + ENSURE_NO_RELOCS (buf); + last_cie = last_fde; + } + else + { + /* Ensure this FDE uses the last CIE encountered. */ + REQUIRE (last_cie); + REQUIRE (hdr.id == (unsigned int) (buf - 4 - last_cie)); + + ENSURE_NO_RELOCS (buf); + REQUIRE (GET_RELOC (buf)); + + if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie)) + /* This is a FDE against a discarded section. It should + be deleted. */ + this_inf->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++; + } + /* Skip the initial location and address range. */ + start = buf; + length = get_DW_EH_PE_width (cie.fde_encoding, ptr_size); + REQUIRE (skip_bytes (&buf, end, 2 * length)); + + /* Skip the augmentation size, if present. */ + if (cie.augmentation[0] == 'z') + REQUIRE (read_uleb128 (&buf, end, &length)); + else + length = 0; + + /* Of the supported augmentation characters above, only 'L' + adds augmentation data to the FDE. This code would need to + be adjusted if any future augmentations do the same thing. */ + if (cie.lsda_encoding != DW_EH_PE_omit) + { + this_inf->lsda_offset = buf - start; + /* If there's no 'z' augmentation, we don't know where the + CFA insns begin. Assume no padding. */ + if (cie.augmentation[0] != 'z') + length = end - buf; + } + + /* Skip over the augmentation data. */ + REQUIRE (skip_bytes (&buf, end, length)); + insns = buf; + + buf = last_fde + 4 + hdr.length; + SKIP_RELOCS (buf); + } + + /* Try to interpret the CFA instructions and find the first + padding nop. Shrink this_inf's size so that it doesn't + including the padding. */ + length = get_DW_EH_PE_width (cie.fde_encoding, ptr_size); + insns = skip_non_nops (insns, end, length); + if (insns != 0) + this_inf->size -= end - insns; + + this_inf->fde_encoding = cie.fde_encoding; + this_inf->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_inf = hdr_info->last_cie_inf; + for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) + if (!ent->removed) + { + if (ent->cie) + last_cie_inf = ent; + else + ent->cie_inf = last_cie_inf; + ent->new_offset = offset; + offset += size_of_output_cie_fde (ent, ptr_size); + } + hdr_info->last_cie_inf = last_cie_inf; + + /* Resize the sec as needed. */ + sec->rawsize = sec->size; + sec->size = offset; + if (sec->size == 0) + sec->flags |= SEC_EXCLUDE; + + free (ehbuf); + return offset != sec->rawsize; + +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; + +#undef REQUIRE +} + +/* 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 (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->size = EH_FRAME_HDR_SIZE; + if (hdr_info->table) + sec->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 when the dynamic symbol table has been sized it is too late + to strip sections. */ + +bfd_boolean +_bfd_elf_maybe_strip_eh_frame_hdr (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->size > 8 && !bfd_is_abs_section (o->output_section)) + break; + } + + if (abfd == NULL) + { + hdr_info->hdr_sec->flags |= SEC_EXCLUDE; + 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 (bfd *output_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info, + asection *sec, + bfd_vma offset) +{ + struct eh_frame_sec_info *sec_info; + struct elf_link_hash_table *htab; + struct eh_frame_hdr_info *hdr_info; + unsigned int lo, hi, mid; + + if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME) + return offset; + sec_info = elf_section_data (sec)->sec_info; + + if (offset >= sec->rawsize) + return offset - sec->rawsize + sec->size; + + htab = elf_hash_table (info); + hdr_info = &htab->eh_info; + if (hdr_info->offsets_adjusted) + offset += sec->output_offset; + + 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].cie + && sec_info->entry[mid].cie_inf->make_relative + && 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].cie + && sec_info->entry[mid].cie_inf->make_lsda_relative + && (offset == (sec_info->entry[mid].offset + 8 + + sec_info->entry[mid].lsda_offset)) + && (sec_info->entry[mid].cie_inf->need_lsda_relative + || !hdr_info->offsets_adjusted)) + { + sec_info->entry[mid].cie_inf->need_lsda_relative = 1; + return (bfd_vma) -2; + } + + if (hdr_info->offsets_adjusted) + offset -= sec->output_offset; + /* Any new augmentation bytes go before the first relocation. */ + return (offset + sec_info->entry[mid].new_offset + - sec_info->entry[mid].offset + + extra_augmentation_string_bytes (sec_info->entry + mid) + + extra_augmentation_data_bytes (sec_info->entry + mid)); +} + +/* Write out .eh_frame section. This is called with the relocated + contents. */ + +bfd_boolean +_bfd_elf_write_section_eh_frame (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 ptr_size; + struct eh_cie_fde *ent; + + if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME) + return bfd_set_section_contents (abfd, sec->output_section, contents, + sec->output_offset, sec->size); + + ptr_size = (get_elf_backend_data (abfd) + ->elf_backend_eh_frame_address_size (abfd, sec)); + BFD_ASSERT (ptr_size != 0); + + sec_info = elf_section_data (sec)->sec_info; + htab = elf_hash_table (info); + hdr_info = &htab->eh_info; + + /* First convert all offsets to output section offsets, so that a + CIE offset is valid if the CIE is used by a FDE from some other + section. This can happen when duplicate CIEs are deleted in + _bfd_elf_discard_section_eh_frame. We do all sections here because + this function might not be called on sections in the same order as + _bfd_elf_discard_section_eh_frame. */ + if (!hdr_info->offsets_adjusted) + { + bfd *ibfd; + asection *eh; + struct eh_frame_sec_info *eh_inf; + + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + { + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || (ibfd->flags & DYNAMIC) != 0) + continue; + + eh = bfd_get_section_by_name (ibfd, ".eh_frame"); + if (eh == NULL || eh->sec_info_type != ELF_INFO_TYPE_EH_FRAME) + continue; + + eh_inf = elf_section_data (eh)->sec_info; + for (ent = eh_inf->entry; ent < eh_inf->entry + eh_inf->count; ++ent) + { + ent->offset += eh->output_offset; + ent->new_offset += eh->output_offset; + } + } + hdr_info->offsets_adjusted = TRUE; + } + + 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; + + /* The new offsets can be bigger or smaller than the original offsets. + We therefore need to make two passes over the section: one backward + pass to move entries up and one forward pass to move entries down. + The two passes won't interfere with each other because entries are + not reordered */ + for (ent = sec_info->entry + sec_info->count; ent-- != sec_info->entry;) + if (!ent->removed && ent->new_offset > ent->offset) + memmove (contents + ent->new_offset - sec->output_offset, + contents + ent->offset - sec->output_offset, ent->size); + + for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) + if (!ent->removed && ent->new_offset < ent->offset) + memmove (contents + ent->new_offset - sec->output_offset, + contents + ent->offset - sec->output_offset, ent->size); + + for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) + { + unsigned char *buf, *end; + unsigned int new_size; + + if (ent->removed) + continue; + + if (ent->size == 4) + { + /* Any terminating FDE must be at the end of the section. */ + BFD_ASSERT (ent == sec_info->entry + sec_info->count - 1); + continue; + } + + buf = contents + ent->new_offset - sec->output_offset; + end = buf + ent->size; + new_size = size_of_output_cie_fde (ent, ptr_size); + + /* Update the size. It may be shrinked. */ + bfd_put_32 (abfd, new_size - 4, buf); + + /* Filling the extra bytes with DW_CFA_nops. */ + if (new_size != ent->size) + memset (end, 0, new_size - ent->size); + + if (ent->cie) + { + /* CIE */ + if (ent->make_relative + || ent->need_lsda_relative + || ent->per_encoding_relative) + { + char *aug; + unsigned int action, extra_string, extra_data; + unsigned int per_width, per_encoding; + + /* Need to find 'R' or 'L' augmentation's argument and modify + DW_EH_PE_* value. */ + action = ((ent->make_relative ? 1 : 0) + | (ent->need_lsda_relative ? 2 : 0) + | (ent->per_encoding_relative ? 4 : 0)); + extra_string = extra_augmentation_string_bytes (ent); + extra_data = extra_augmentation_data_bytes (ent); + + /* Skip length, id and version. */ + buf += 9; + aug = (char *) buf; + buf += strlen (aug) + 1; + skip_leb128 (&buf, end); + skip_leb128 (&buf, end); + skip_leb128 (&buf, end); + if (*aug == 'z') + { + /* The uleb128 will always be a single byte for the kind + of augmentation strings that we're prepared to handle. */ + *buf++ += extra_data; + aug++; + } + + /* Make room for the new augmentation string and data bytes. */ + memmove (buf + extra_string + extra_data, buf, end - buf); + memmove (aug + extra_string, aug, buf - (bfd_byte *) aug); + buf += extra_string; + end += extra_string + extra_data; + + if (ent->add_augmentation_size) + { + *aug++ = 'z'; + *buf++ = extra_data - 1; + } + if (ent->add_fde_encoding) + { + BFD_ASSERT (action & 1); + *aug++ = 'R'; + *buf++ = DW_EH_PE_pcrel; + action &= ~1; + } + + while (action) + switch (*aug++) + { + case 'L': + if (action & 2) + { + BFD_ASSERT (*buf == ent->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) + == ent->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 val; + + val = read_value (abfd, buf, per_width, + get_DW_EH_PE_signed (per_encoding)); + val += ent->offset - ent->new_offset; + val -= extra_string + extra_data; + write_value (abfd, buf, val, per_width); + action &= ~4; + } + buf += per_width; + break; + case 'R': + if (action & 1) + { + BFD_ASSERT (*buf == ent->fde_encoding); + *buf |= DW_EH_PE_pcrel; + action &= ~1; + } + buf++; + break; + case 'S': + break; + default: + BFD_FAIL (); + } + } + } + else + { + /* FDE */ + bfd_vma value, address; + unsigned int width; + + /* Skip length. */ + buf += 4; + value = ent->new_offset + 4 - ent->cie_inf->new_offset; + bfd_put_32 (abfd, value, buf); + buf += 4; + width = get_DW_EH_PE_width (ent->fde_encoding, ptr_size); + value = read_value (abfd, buf, width, + get_DW_EH_PE_signed (ent->fde_encoding)); + address = value; + if (value) + { + switch (ent->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 += ent->offset - ent->new_offset; + address += sec->output_section->vma + ent->offset + 8; + break; + } + if (ent->cie_inf->make_relative) + value -= sec->output_section->vma + ent->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 + ent->new_offset; + } + + if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel + || ent->cie_inf->need_lsda_relative) + { + buf += ent->lsda_offset; + width = get_DW_EH_PE_width (ent->lsda_encoding, ptr_size); + value = read_value (abfd, buf, width, + get_DW_EH_PE_signed (ent->lsda_encoding)); + if (value) + { + if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel) + value += ent->offset - ent->new_offset; + else if (ent->cie_inf->need_lsda_relative) + value -= (sec->output_section->vma + ent->new_offset + 8 + + ent->lsda_offset); + write_value (abfd, buf, value, width); + } + } + else if (ent->cie_inf->add_augmentation_size) + { + /* Skip the PC and length and insert a zero byte for the + augmentation size. */ + buf += width * 2; + memmove (buf + 1, buf, end - buf); + *buf = 0; + } + } + } + + /* We don't align the section to its section alignment since the + runtime library only expects all CIE/FDE records aligned at + the pointer size. _bfd_elf_discard_section_eh_frame should + have padded CIE/FDE records to multiple of pointer size with + size_of_output_cie_fde. */ + if ((sec->size % ptr_size) != 0) + abort (); + + return bfd_set_section_contents (abfd, sec->output_section, + contents, (file_ptr) sec->output_offset, + sec->size); +} + +/* Helper function used to sort .eh_frame_hdr search table by increasing + VMA of FDE initial location. */ + +static int +vma_compare (const void *a, const void *b) +{ + const struct eh_frame_array_ent *p = a; + const struct eh_frame_array_ent *q = 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 (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; + bfd_vma encoded_eh_frame; + + 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] = get_elf_backend_data (abfd)->elf_backend_encode_eh_address + (abfd, info, eh_frame_sec, 0, sec, 4, + &encoded_eh_frame); /* .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, encoded_eh_frame, 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->size); + free (contents); + return retval; +} + +/* Return the width of FDE addresses. This is the default implementation. */ + +unsigned int +_bfd_elf_eh_frame_address_size (bfd *abfd, asection *sec ATTRIBUTE_UNUSED) +{ + return elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64 ? 8 : 4; +} + +/* Decide whether we can use a PC-relative encoding within the given + EH frame section. This is the default implementation. */ + +bfd_boolean +_bfd_elf_can_make_relative (bfd *input_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + asection *eh_frame_section ATTRIBUTE_UNUSED) +{ + return TRUE; +} + +/* Select an encoding for the given address. Preference is given to + PC-relative addressing modes. */ + +bfd_byte +_bfd_elf_encode_eh_address (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + asection *osec, bfd_vma offset, + asection *loc_sec, bfd_vma loc_offset, + bfd_vma *encoded) +{ + *encoded = osec->vma + offset - + (loc_sec->output_section->vma + loc_sec->output_offset + loc_offset); + return DW_EH_PE_pcrel | DW_EH_PE_sdata4; +} diff --git a/contrib/binutils-2.17/bfd/elf-strtab.c b/contrib/binutils-2.17/bfd/elf-strtab.c new file mode 100644 index 0000000000..a0ce1d79ea --- /dev/null +++ b/contrib/binutils-2.17/bfd/elf-strtab.c @@ -0,0 +1,390 @@ +/* ELF strtab with GC and suffix merging support. + Copyright 2001, 2002, 2003, 2005, 2006 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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. This includes the zero terminator. */ + int len; + unsigned int refcount; + union { + /* Index within the merged section. */ + bfd_size_type index; + /* Entry this is a suffix of (if len < 0). */ + struct elf_strtab_hash_entry *suffix; + } 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; +}; + +/* Routine to create an entry in a section merge hashtab. */ + +static struct bfd_hash_entry * +elf_strtab_hash_newfunc (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_strtab_hash_entry)); + if (entry == NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + entry = bfd_hash_newfunc (entry, table, string); + + if (entry) + { + /* Initialize the local fields. */ + struct elf_strtab_hash_entry *ret; + + ret = (struct elf_strtab_hash_entry *) entry; + ret->u.index = -1; + ret->refcount = 0; + ret->len = 0; + } + + return entry; +} + +/* Create a new hash table. */ + +struct elf_strtab_hash * +_bfd_elf_strtab_init (void) +{ + struct elf_strtab_hash *table; + bfd_size_type amt = sizeof (struct elf_strtab_hash); + + table = bfd_malloc (amt); + if (table == NULL) + return NULL; + + if (!bfd_hash_table_init (&table->table, elf_strtab_hash_newfunc, + sizeof (struct elf_strtab_hash_entry))) + { + free (table); + return NULL; + } + + table->sec_size = 0; + table->size = 1; + table->alloced = 64; + amt = sizeof (struct elf_strtab_hasn_entry *); + table->array = 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 (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 (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; + /* 2G strings lose. */ + BFD_ASSERT (entry->len > 0); + if (tab->size == tab->alloced) + { + bfd_size_type amt = sizeof (struct elf_strtab_hash_entry *); + tab->alloced *= 2; + tab->array = 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 (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 (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 (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 (struct elf_strtab_hash *tab) +{ + return tab->sec_size ? tab->sec_size : tab->size; +} + +bfd_size_type +_bfd_elf_strtab_offset (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 (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 unsigned int len; + + BFD_ASSERT (tab->array[i]->refcount == 0); + len = tab->array[i]->len; + if ((int) len < 0) + continue; + + str = tab->array[i]->root.string; + if (bfd_bwrite (str, len, abfd) != len) + return FALSE; + + off += len; + } + + BFD_ASSERT (off == tab->sec_size); + return TRUE; +} + +/* Compare two elf_strtab_hash_entry structures. Called via qsort. */ + +static int +strrevcmp (const void *a, const void *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; + unsigned int lenA = A->len; + unsigned int lenB = B->len; + const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1; + const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1; + int l = lenA < lenB ? lenA : lenB; + + while (l) + { + if (*s != *t) + return (int) *s - (int) *t; + s--; + t--; + l--; + } + return lenA - lenB; +} + +static inline int +is_suffix (const struct elf_strtab_hash_entry *A, + const struct elf_strtab_hash_entry *B) +{ + 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 - 1) == 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 (struct elf_strtab_hash *tab) +{ + struct elf_strtab_hash_entry **array, **a, *e; + bfd_size_type size, amt; + + /* 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; + + /* Sort the strings by suffix and length. */ + amt = tab->size * sizeof (struct elf_strtab_hash_entry *); + array = bfd_malloc (amt); + if (array == NULL) + goto alloc_failure; + + for (i = 1, a = array; i < tab->size; ++i) + { + e = tab->array[i]; + if (e->refcount) + { + *a++ = e; + /* Adjust the length to not include the zero terminator. */ + e->len -= 1; + } + else + e->len = 0; + } + + size = a - array; + if (size != 0) + { + qsort (array, size, sizeof (struct elf_strtab_hash_entry *), strrevcmp); + + /* Loop over the sorted array and merge suffixes. Start from the + end because we want eg. + + s1 -> "d" + s2 -> "bcd" + s3 -> "abcd" + + to end up as + + s3 -> "abcd" + s2 _____^ + s1 _______^ + + ie. we don't want s1 pointing into the old s2. */ + e = *--a; + e->len += 1; + while (--a >= array) + { + struct elf_strtab_hash_entry *cmp = *a; + + cmp->len += 1; + if (is_suffix (e, cmp)) + { + cmp->u.suffix = e; + cmp->len = -cmp->len; + } + else + e = cmp; + } + } + +alloc_failure: + if (array) + free (array); + + /* 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 > 0) + { + e->u.index = size; + size += e->len; + } + } + + tab->sec_size = size; + + /* Adjust the rest. */ + for (i = 1; i < tab->size; ++i) + { + e = tab->array[i]; + if (e->refcount && e->len < 0) + e->u.index = e->u.suffix->u.index + (e->u.suffix->len + e->len); + } +} diff --git a/contrib/binutils-2.17/bfd/elf-vxworks.c b/contrib/binutils-2.17/bfd/elf-vxworks.c new file mode 100644 index 0000000000..90e620a905 --- /dev/null +++ b/contrib/binutils-2.17/bfd/elf-vxworks.c @@ -0,0 +1,213 @@ +/* VxWorks support for ELF + Copyright 2005 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 provides routines used by all VxWorks targets. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf-vxworks.h" + +/* Tweak magic VxWorks symbols as they are loaded. */ +bfd_boolean +elf_vxworks_add_symbol_hook (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info, + Elf_Internal_Sym *sym, + const char **namep, + flagword *flagsp, + asection **secp ATTRIBUTE_UNUSED, + bfd_vma *valp ATTRIBUTE_UNUSED) +{ + /* Ideally these "magic" symbols would be exported by libc.so.1 + which would be found via a DT_NEEDED tag, and then handled + specially by the linker at runtime. Except shared libraries + don't even link to libc.so.1 by default... + If the symbol is imported from, or will be put in a shared library, + give the symbol weak binding to get the desired samantics. + This transformation will be undone in + elf_i386_vxworks_link_output_symbol_hook. */ + if ((info->shared || abfd->flags & DYNAMIC) + && (strcmp (*namep, "__GOTT_INDEX__") == 0 + || strcmp (*namep, "__GOTT_BASE__") == 0)) + { + sym->st_info = ELF_ST_INFO (STB_WEAK, ELF_ST_TYPE (sym->st_info)); + *flagsp |= BSF_WEAK; + } + + return TRUE; +} + +/* Perform VxWorks-specific handling of the create_dynamic_sections hook. + When creating an executable, set *SRELPLT2_OUT to the .rel(a).plt.unloaded + section. */ + +bfd_boolean +elf_vxworks_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info, + asection **srelplt2_out) +{ + struct elf_link_hash_table *htab; + const struct elf_backend_data *bed; + asection *s; + + htab = elf_hash_table (info); + bed = get_elf_backend_data (dynobj); + + if (!info->shared) + { + s = bfd_make_section_with_flags (dynobj, + bed->default_use_rela_p + ? ".rela.plt.unloaded" + : ".rel.plt.unloaded", + SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_READONLY | SEC_LINKER_CREATED); + if (s == NULL + || !bfd_set_section_alignment (dynobj, s, bed->s->log_file_align)) + return FALSE; + + *srelplt2_out = s; + } + + /* Mark the GOT and PLT symbols as having relocations; they might + not, but we won't know for sure until we build the GOT in + finish_dynamic_symbol. Also make sure that the GOT symbol + is entered into the dynamic symbol table; the loader uses it + to initialize __GOTT_BASE__[__GOTT_INDEX__]. */ + if (htab->hgot) + { + htab->hgot->indx = -2; + htab->hgot->other &= ~ELF_ST_VISIBILITY (-1); + htab->hgot->forced_local = 0; + if (!bfd_elf_link_record_dynamic_symbol (info, htab->hgot)) + return FALSE; + } + if (htab->hplt) + { + htab->hplt->indx = -2; + htab->hplt->type = STT_FUNC; + } + + return TRUE; +} + +/* Tweak magic VxWorks symbols as they are written to the output file. */ +bfd_boolean +elf_vxworks_link_output_symbol_hook (struct bfd_link_info *info + ATTRIBUTE_UNUSED, + const char *name, + Elf_Internal_Sym *sym, + asection *input_sec ATTRIBUTE_UNUSED, + struct elf_link_hash_entry *h + ATTRIBUTE_UNUSED) +{ + /* Ignore the first dummy symbol. */ + if (!name) + return TRUE; + + /* Reverse the effects of the hack in elf_vxworks_add_symbol_hook. */ + if (strcmp (name, "__GOTT_INDEX__") == 0 + || strcmp (name, "__GOTT_BASE__") == 0) + sym->st_info = ELF_ST_INFO (STB_GLOBAL, ELF_ST_TYPE (sym->st_info)); + + return TRUE; +} + + +/* Copy relocations into the output file. Fixes up relocations againt PLT + entries, then calls the generic routine. */ + +bfd_boolean +elf_vxworks_emit_relocs (bfd *output_bfd, + asection *input_section, + Elf_Internal_Shdr *input_rel_hdr, + Elf_Internal_Rela *internal_relocs, + struct elf_link_hash_entry **rel_hash) +{ + const struct elf_backend_data *bed; + Elf_Internal_Rela *irela; + Elf_Internal_Rela *irelaend; + int j; + + bed = get_elf_backend_data (output_bfd); + + irela = internal_relocs; + irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr) + * bed->s->int_rels_per_ext_rel); + while (irela < irelaend) + { + if ((output_bfd->flags & (DYNAMIC|EXEC_P)) + && *rel_hash + && (*rel_hash)->def_dynamic + && !(*rel_hash)->def_regular + && (*rel_hash)->root.type == bfd_link_hash_defined + && (*rel_hash)->root.u.def.section->output_section != NULL) + { + /* This is a relocation from an executable or shared library + against a symbol in a different shared library. We are + creating a definition in the output file but it does not come + from any of our normal (.o) files. ie. a PLT stub. + Normally this would be a relocation against against SHN_UNDEF + with the VMA of the PLT stub. This upsets the VxWorks loader. + Convert it to a section-relative relocation. + This gets some other symbols (for instance .dynbss), + but is conservatively correct. */ + for (j = 0; j < bed->s->int_rels_per_ext_rel; j++) + { + asection *sec = (*rel_hash)->root.u.def.section; + int this_idx = + elf_section_data (sec->output_section)->this_idx; + + irela[j].r_info = ELF32_R_INFO (this_idx, + ELF32_R_TYPE (irela[j].r_info)); + irela[j].r_addend += (*rel_hash)->root.u.def.value; + irela[j].r_addend += sec->output_offset; + } + /* Stop the generic routine adjusting this entry. */ + *rel_hash = NULL; + } + irela += bed->s->int_rels_per_ext_rel; + rel_hash++; + } + return _bfd_elf_link_output_relocs (output_bfd, input_section, + input_rel_hdr, internal_relocs, + rel_hash); +} + + +/* Set the sh_link and sh_info fields on the static plt relocation secton. */ + +void +elf_vxworks_final_write_processing (bfd *abfd, + bfd_boolean linker ATTRIBUTE_UNUSED) +{ + asection * sec; + struct bfd_elf_section_data *d; + + sec = bfd_get_section_by_name (abfd, ".rel.plt.unloaded"); + if (!sec) + sec = bfd_get_section_by_name (abfd, ".rela.plt.unloaded"); + if (!sec) + return; + d = elf_section_data (sec); + d->this_hdr.sh_link = elf_tdata (abfd)->symtab_section; + sec = bfd_get_section_by_name (abfd, ".plt"); + if (sec) + d->this_hdr.sh_info = elf_section_data (sec)->this_idx; +} diff --git a/contrib/binutils-2.17/bfd/elf-vxworks.h b/contrib/binutils-2.17/bfd/elf-vxworks.h new file mode 100644 index 0000000000..c8ea0094ee --- /dev/null +++ b/contrib/binutils-2.17/bfd/elf-vxworks.h @@ -0,0 +1,35 @@ +/* VxWorks support for ELF + Copyright 2005 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 "elf/common.h" +#include "elf/internal.h" + +bfd_boolean elf_vxworks_add_symbol_hook + (bfd *, struct bfd_link_info *, Elf_Internal_Sym *, const char **, + flagword *, asection **, bfd_vma *); +bfd_boolean elf_vxworks_link_output_symbol_hook + (struct bfd_link_info *, const char *name, Elf_Internal_Sym *, + asection *, struct elf_link_hash_entry *); +bfd_boolean elf_vxworks_emit_relocs + (bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *, + struct elf_link_hash_entry **); +void elf_vxworks_final_write_processing (bfd *, bfd_boolean); +bfd_boolean elf_vxworks_create_dynamic_sections + (bfd *, struct bfd_link_info *, asection **); diff --git a/contrib/binutils-2.17/bfd/elf.c b/contrib/binutils-2.17/bfd/elf.c new file mode 100644 index 0000000000..9e48f66e90 --- /dev/null +++ b/contrib/binutils-2.17/bfd/elf.c @@ -0,0 +1,8740 @@ +/* ELF executable support for BFD. + + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2005, 2006 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 int elf_sort_sections (const void *, const void *); +static bfd_boolean assign_file_positions_except_relocs (bfd *, struct bfd_link_info *); +static bfd_boolean prep_headers (bfd *); +static bfd_boolean swap_out_syms (bfd *, struct bfd_strtab_hash **, int) ; +static bfd_boolean elfcore_read_notes (bfd *, file_ptr, bfd_size_type) ; + +/* 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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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; +} + +bfd_boolean +bfd_elf_mkobject (bfd *abfd) +{ + /* This just does initialization. */ + /* coff_mkobject zalloc's space for tdata.coff_obj_data ... */ + elf_tdata (abfd) = bfd_zalloc (abfd, sizeof (struct elf_obj_tdata)); + 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 (bfd *abfd) +{ + /* I think this can be done just like an object file. */ + return bfd_elf_mkobject (abfd); +} + +char * +bfd_elf_get_str_section (bfd *abfd, unsigned int shindex) +{ + Elf_Internal_Shdr **i_shdrp; + bfd_byte *shstrtab = NULL; + file_ptr offset; + bfd_size_type shstrtabsize; + + i_shdrp = elf_elfsections (abfd); + if (i_shdrp == 0 || i_shdrp[shindex] == 0) + return NULL; + + shstrtab = 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; + + /* Allocate and clear an extra byte at the end, to prevent crashes + in case the string table is not terminated. */ + if (shstrtabsize + 1 == 0 + || (shstrtab = bfd_alloc (abfd, shstrtabsize + 1)) == NULL + || bfd_seek (abfd, offset, SEEK_SET) != 0) + shstrtab = NULL; + else if (bfd_bread (shstrtab, shstrtabsize, abfd) != shstrtabsize) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_file_truncated); + shstrtab = NULL; + } + else + shstrtab[shstrtabsize] = '\0'; + i_shdrp[shindex]->contents = shstrtab; + } + return (char *) shstrtab; +} + +char * +bfd_elf_string_from_elf_section (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) + { + unsigned int shstrndx = elf_elfheader(abfd)->e_shstrndx; + (*_bfd_error_handler) + (_("%B: invalid string offset %u >= %lu for section `%s'"), + abfd, strindex, (unsigned long) hdr->sh_size, + (shindex == shstrndx && strindex == hdr->sh_name + ? ".shstrtab" + : bfd_elf_string_from_elf_section (abfd, shstrndx, 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 (bfd *ibfd, + Elf_Internal_Shdr *symtab_hdr, + size_t symcount, + size_t symoffset, + Elf_Internal_Sym *intsym_buf, + void *extsym_buf, + Elf_External_Sym_Shndx *extshndx_buf) +{ + Elf_Internal_Shdr *shndx_hdr; + void *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; + const 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_malloc2 (symcount, extsym_size); + 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 = bfd_malloc2 (symcount, + sizeof (Elf_External_Sym_Shndx)); + 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) + { + intsym_buf = bfd_malloc2 (symcount, sizeof (Elf_Internal_Sym)); + 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, 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_sym_name (bfd *abfd, + Elf_Internal_Shdr *symtab_hdr, + Elf_Internal_Sym *isym, + asection *sym_sec) +{ + const char *name; + unsigned int iname = isym->st_name; + unsigned int shindex = symtab_hdr->sh_link; + + if (iname == 0 && ELF_ST_TYPE (isym->st_info) == STT_SECTION + /* Check for a bogus st_shndx to avoid crashing. */ + && isym->st_shndx < elf_numsections (abfd) + && !(isym->st_shndx >= SHN_LORESERVE && isym->st_shndx <= SHN_HIRESERVE)) + { + iname = elf_elfsections (abfd)[isym->st_shndx]->sh_name; + shindex = elf_elfheader (abfd)->e_shstrndx; + } + + name = bfd_elf_string_from_elf_section (abfd, shindex, iname); + if (name == NULL) + name = "(null)"; + else if (sym_sec && *name == '\0') + name = bfd_section_name (abfd, sym_sec); + + return name; +} + +/* 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 (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. Make sure + that it is a symbol table section. */ + hdr = elf_elfsections (abfd) [ghdr->sh_link]; + if (hdr->sh_type != SHT_SYMTAB + || ! 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_sym_name (abfd, hdr, &isym, NULL); +} + +/* Set next_in_group list pointer, and group name for NEWSECT. */ + +static bfd_boolean +setup_group (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; + } + else + { + /* We keep a list of elf section headers for group sections, + so we can find them quickly. */ + bfd_size_type amt; + + elf_tdata (abfd)->num_group = num_group; + elf_tdata (abfd)->group_sect_ptr + = bfd_alloc2 (abfd, num_group, sizeof (Elf_Internal_Shdr *)); + 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_alloc2 (abfd, shdr->sh_size, + sizeof (*dest) / 4); + 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) + (_("%B: invalid SHT_GROUP entry"), 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) (_("%B: no group info for section %A"), + abfd, newsect); + } + return TRUE; +} + +bfd_boolean +_bfd_elf_setup_sections (bfd *abfd) +{ + unsigned int i; + unsigned int num_group = elf_tdata (abfd)->num_group; + bfd_boolean result = TRUE; + asection *s; + + /* Process SHF_LINK_ORDER. */ + for (s = abfd->sections; s != NULL; s = s->next) + { + Elf_Internal_Shdr *this_hdr = &elf_section_data (s)->this_hdr; + if ((this_hdr->sh_flags & SHF_LINK_ORDER) != 0) + { + unsigned int elfsec = this_hdr->sh_link; + /* FIXME: The old Intel compiler and old strip/objcopy may + not set the sh_link or sh_info fields. Hence we could + get the situation where elfsec is 0. */ + if (elfsec == 0) + { + const struct elf_backend_data *bed + = get_elf_backend_data (abfd); + if (bed->link_order_error_handler) + bed->link_order_error_handler + (_("%B: warning: sh_link not set for section `%A'"), + abfd, s); + } + else + { + asection *link; + + this_hdr = elf_elfsections (abfd)[elfsec]; + + /* PR 1991, 2008: + Some strip/objcopy may leave an incorrect value in + sh_link. We don't want to proceed. */ + link = this_hdr->bfd_section; + if (link == NULL) + { + (*_bfd_error_handler) + (_("%B: sh_link [%d] in section `%A' is incorrect"), + s->owner, s, elfsec); + result = FALSE; + } + + elf_linked_to_section (s) = link; + } + } + } + + /* Process section groups. */ + if (num_group == (unsigned) -1) + return result; + + 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; + + while (--n_elt != 0) + if ((++idx)->shdr->bfd_section) + elf_sec_group (idx->shdr->bfd_section) = shdr->bfd_section; + else if (idx->shdr->sh_type == SHT_RELA + || idx->shdr->sh_type == SHT_REL) + /* We won't include relocation sections in section groups in + output object files. We adjust the group section size here + so that relocatable link will work correctly when + relocation sections are in section group in input object + files. */ + shdr->bfd_section->size -= 4; + else + { + /* There are some unknown sections in the group. */ + (*_bfd_error_handler) + (_("%B: unknown [%d] section `%s' in group [%s]"), + abfd, + (unsigned int) idx->shdr->sh_type, + bfd_elf_string_from_elf_section (abfd, + (elf_elfheader (abfd) + ->e_shstrndx), + idx->shdr->sh_name), + shdr->bfd_section->name); + result = FALSE; + } + } + return result; +} + +bfd_boolean +bfd_elf_is_group_section (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec) +{ + return elf_next_in_group (sec) != NULL; +} + +/* 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 (bfd *abfd, + Elf_Internal_Shdr *hdr, + const char *name, + int shindex) +{ + asection *newsect; + flagword flags; + const 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; + + hdr->bfd_section = newsect; + elf_section_data (newsect)->this_hdr = *hdr; + elf_section_data (newsect)->this_idx = shindex; + + /* Always use the real type/flags. */ + elf_section_type (newsect) = hdr->sh_type; + elf_section_flags (newsect) = hdr->sh_flags; + + 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; + + if ((flags & SEC_ALLOC) == 0) + { + /* The debugging sections appear to be recognized only by name, + not any sort of flag. Their SEC_ALLOC bits are cleared. */ + static const struct + { + const char *name; + int len; + } debug_sections [] = + { + { "debug", 5 }, /* 'd' */ + { NULL, 0 }, /* 'e' */ + { NULL, 0 }, /* 'f' */ + { "gnu.linkonce.wi.", 17 }, /* 'g' */ + { NULL, 0 }, /* 'h' */ + { NULL, 0 }, /* 'i' */ + { NULL, 0 }, /* 'j' */ + { NULL, 0 }, /* 'k' */ + { "line", 4 }, /* 'l' */ + { NULL, 0 }, /* 'm' */ + { NULL, 0 }, /* 'n' */ + { NULL, 0 }, /* 'o' */ + { NULL, 0 }, /* 'p' */ + { NULL, 0 }, /* 'q' */ + { NULL, 0 }, /* 'r' */ + { "stab", 4 } /* 's' */ + }; + + if (name [0] == '.') + { + int i = name [1] - 'd'; + if (i >= 0 + && i < (int) ARRAY_SIZE (debug_sections) + && debug_sections [i].name != NULL + && strncmp (&name [1], debug_sections [i].name, + debug_sections [i].len) == 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; + } + } + } + } + + 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 (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 relocatable + 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 + relocatable output against an external symbol. */ + +bfd_reloc_status_type +bfd_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED, + arelent *reloc_entry, + asymbol *symbol, + void *data ATTRIBUTE_UNUSED, + asection *input_section, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + if (output_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 (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 (bfd *abfd, struct bfd_link_info *info) +{ + bfd *ibfd; + asection *sec; + + if (!is_elf_hash_table (info->hash)) + return FALSE; + + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + if ((ibfd->flags & DYNAMIC) == 0) + for (sec = ibfd->sections; sec != NULL; sec = sec->next) + if ((sec->flags & SEC_MERGE) != 0 + && !bfd_is_abs_section (sec->output_section)) + { + struct bfd_elf_section_data *secdata; + + secdata = elf_section_data (sec); + if (! _bfd_add_merge_section (abfd, + &elf_hash_table (info)->merge_info, + sec, &secdata->sec_info)) + return FALSE; + else if (secdata->sec_info) + sec->sec_info_type = ELF_INFO_TYPE_MERGE; + } + + if (elf_hash_table (info)->merge_info != NULL) + _bfd_merge_sections (abfd, info, elf_hash_table (info)->merge_info, + merge_sections_remove_hook); + return TRUE; +} + +void +_bfd_elf_link_just_syms (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->hash)) + 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 (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; +} + +static const char * +get_segment_type (unsigned int p_type) +{ + const char *pt; + switch (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; + case PT_GNU_STACK: pt = "STACK"; break; + case PT_GNU_RELRO: pt = "RELRO"; break; + default: pt = NULL; break; + } + return pt; +} + +/* Print out the program headers. */ + +bfd_boolean +_bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) +{ + FILE *f = 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 = get_segment_type (p->p_type); + char buf[20]; + + if (pt == NULL) + { + sprintf (buf, "0x%lx", p->p_type); + pt = buf; + } + 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) (bfd *, const void *, Elf_Internal_Dyn *); + + fprintf (f, _("\nDynamic Section:\n")); + + if (!bfd_malloc_and_get_section (abfd, s, &dynbuf)) + 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->size; + for (; extdyn < extdynend; extdyn += extdynsize) + { + Elf_Internal_Dyn dyn; + const char *name; + char ab[20]; + bfd_boolean stringp; + + (*swap_dyn_in) (abfd, 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, FALSE)) + 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 ? t->vd_nodename : ""); + if (t->vd_auxptr != NULL && 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 ? 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 ? 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 ? 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 (bfd *abfd, + void *filep, + asymbol *symbol, + bfd_print_symbol_type how) +{ + 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; + const 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, 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 (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->got = htab->init_got_refcount; + ret->plt = htab->init_plt_refcount; + memset (&ret->size, 0, (sizeof (struct elf_link_hash_entry) + - offsetof (struct elf_link_hash_entry, size))); + /* 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->non_elf = 1; + } + + 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 (struct bfd_link_info *info, + struct elf_link_hash_entry *dir, + struct elf_link_hash_entry *ind) +{ + struct elf_link_hash_table *htab; + + /* Copy down any references that we may have already seen to the + symbol which just became indirect. */ + + dir->ref_dynamic |= ind->ref_dynamic; + dir->ref_regular |= ind->ref_regular; + dir->ref_regular_nonweak |= ind->ref_regular_nonweak; + dir->non_got_ref |= ind->non_got_ref; + dir->needs_plt |= ind->needs_plt; + dir->pointer_equality_needed |= ind->pointer_equality_needed; + + 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. */ + htab = elf_hash_table (info); + if (ind->got.refcount > htab->init_got_refcount.refcount) + { + if (dir->got.refcount < 0) + dir->got.refcount = 0; + dir->got.refcount += ind->got.refcount; + ind->got.refcount = htab->init_got_refcount.refcount; + } + + if (ind->plt.refcount > htab->init_plt_refcount.refcount) + { + if (dir->plt.refcount < 0) + dir->plt.refcount = 0; + dir->plt.refcount += ind->plt.refcount; + ind->plt.refcount = htab->init_plt_refcount.refcount; + } + + if (ind->dynindx != -1) + { + if (dir->dynindx != -1) + _bfd_elf_strtab_delref (htab->dynstr, dir->dynstr_index); + dir->dynindx = ind->dynindx; + dir->dynstr_index = ind->dynstr_index; + ind->dynindx = -1; + ind->dynstr_index = 0; + } +} + +void +_bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *h, + bfd_boolean force_local) +{ + h->plt = elf_hash_table (info)->init_plt_offset; + h->needs_plt = 0; + if (force_local) + { + h->forced_local = 1; + 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 + (struct elf_link_hash_table *table, + bfd *abfd, + struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int entsize) +{ + bfd_boolean ret; + int can_refcount = get_elf_backend_data (abfd)->can_refcount; + + table->dynamic_sections_created = FALSE; + table->dynobj = NULL; + table->init_got_refcount.refcount = can_refcount - 1; + table->init_plt_refcount.refcount = can_refcount - 1; + table->init_got_offset.offset = -(bfd_vma) 1; + table->init_plt_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->merge_info = NULL; + memset (&table->stab_info, 0, sizeof (table->stab_info)); + memset (&table->eh_info, 0, sizeof (table->eh_info)); + table->dynlocal = NULL; + table->runpath = NULL; + table->tls_sec = NULL; + table->tls_size = 0; + table->loaded = NULL; + table->is_relocatable_executable = FALSE; + + ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize); + 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 (bfd *abfd) +{ + struct elf_link_hash_table *ret; + bfd_size_type amt = sizeof (struct elf_link_hash_table); + + ret = bfd_malloc (amt); + if (ret == NULL) + return NULL; + + if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc, + sizeof (struct elf_link_hash_entry))) + { + 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. */ + +void +bfd_elf_set_dt_needed_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; +} + +int +bfd_elf_get_dyn_lib_class (bfd *abfd) +{ + int lib_class; + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && bfd_get_format (abfd) == bfd_object) + lib_class = elf_dyn_lib_class (abfd); + else + lib_class = 0; + return lib_class; +} + +void +bfd_elf_set_dyn_lib_class (bfd *abfd, int lib_class) +{ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && bfd_get_format (abfd) == bfd_object) + elf_dyn_lib_class (abfd) = lib_class; +} + +/* 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 (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info) +{ + if (! is_elf_hash_table (info->hash)) + 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 (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info) +{ + if (! is_elf_hash_table (info->hash)) + 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 (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 (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) (bfd *, const void *, 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->size == 0) + return TRUE; + + if (!bfd_malloc_and_get_section (abfd, s, &dynbuf)) + 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->size; + for (; extdyn < extdynend; extdyn += extdynsize) + { + Elf_Internal_Dyn dyn; + + (*swap_dyn_in) (abfd, 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 = 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 (void) +{ + struct bfd_strtab_hash *ret; + + ret = _bfd_stringtab_init (); + if (ret != NULL) + { + bfd_size_type loc; + + loc = _bfd_stringtab_add (ret, "", TRUE, FALSE); + BFD_ASSERT (loc == 0 || loc == (bfd_size_type) -1); + if (loc == (bfd_size_type) -1) + { + _bfd_stringtab_free (ret); + ret = NULL; + } + } + return ret; +} + +/* ELF .o/exec file reading */ + +/* Create a new bfd section from an ELF section header. */ + +bfd_boolean +bfd_section_from_shdr (bfd *abfd, unsigned int shindex) +{ + Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[shindex]; + Elf_Internal_Ehdr *ehdr = elf_elfheader (abfd); + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + const char *name; + + name = bfd_elf_string_from_elf_section (abfd, + elf_elfheader (abfd)->e_shstrndx, + hdr->sh_name); + if (name == NULL) + return FALSE; + + 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. */ + case SHT_GNU_LIBLIST: /* .gnu.liblist section. */ + return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + + case SHT_DYNAMIC: /* Dynamic linking information. */ + if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) + return FALSE; + if (hdr->sh_link > elf_numsections (abfd) + || elf_elfsections (abfd)[hdr->sh_link] == NULL) + 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; + + if (hdr->sh_entsize != bed->s->sizeof_sym) + return FALSE; + 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 relocatable 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, + shindex)) + return FALSE; + + /* Go looking for SHT_SYMTAB_SHNDX too, since if there is one we + can't read symbols without that section loaded as well. It + is most likely specified by the next section header. */ + if (elf_elfsections (abfd)[elf_symtab_shndx (abfd)]->sh_link != shindex) + { + unsigned int i, num_sec; + + num_sec = elf_numsections (abfd); + for (i = shindex + 1; i < num_sec; i++) + { + Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i]; + if (hdr2->sh_type == SHT_SYMTAB_SHNDX + && hdr2->sh_link == shindex) + break; + } + if (i == num_sec) + for (i = 1; i < shindex; i++) + { + Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i]; + if (hdr2->sh_type == SHT_SYMTAB_SHNDX + && hdr2->sh_link == shindex) + break; + } + if (i != shindex) + return bfd_section_from_shdr (abfd, i); + } + return TRUE; + + case SHT_DYNSYM: /* A dynamic symbol table */ + if (elf_dynsymtab (abfd) == shindex) + return TRUE; + + if (hdr->sh_entsize != bed->s->sizeof_sym) + return FALSE; + 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, shindex); + + case SHT_SYMTAB_SHNDX: /* Symbol section indices when >64k sections */ + if (elf_symtab_shndx (abfd) == shindex) + return TRUE; + + BFD_ASSERT (elf_symtab_shndx (abfd) == 0); + elf_symtab_shndx (abfd) = shindex; + elf_tdata (abfd)->symtab_shndx_hdr = *hdr; + elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->symtab_shndx_hdr; + return TRUE; + + 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; + } + if (elf_elfsections (abfd)[elf_onesymtab (abfd)]->sh_link == shindex) + { + symtab_strtab: + elf_tdata (abfd)->strtab_hdr = *hdr; + elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->strtab_hdr; + return TRUE; + } + if (elf_elfsections (abfd)[elf_dynsymtab (abfd)]->sh_link == shindex) + { + dynsymtab_strtab: + elf_tdata (abfd)->dynstrtab_hdr = *hdr; + hdr = &elf_tdata (abfd)->dynstrtab_hdr; + elf_elfsections (abfd)[shindex] = hdr; + /* We also treat this as a regular section, so that objcopy + can handle it. */ + return _bfd_elf_make_section_from_shdr (abfd, hdr, name, + shindex); + } + + /* If the string table isn't one of the above, then treat it as a + regular section. We need to scan all the headers to be sure, + just in case this strtab section appeared before the above. */ + if (elf_onesymtab (abfd) == 0 || elf_dynsymtab (abfd) == 0) + { + 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) + { + /* Prevent endless recursion on broken objects. */ + if (i == shindex) + return FALSE; + if (! bfd_section_from_shdr (abfd, i)) + return FALSE; + if (elf_onesymtab (abfd) == i) + goto symtab_strtab; + if (elf_dynsymtab (abfd) == i) + goto dynsymtab_strtab; + } + } + } + return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + + 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); + + if (hdr->sh_entsize + != (bfd_size_type) (hdr->sh_type == SHT_REL + ? bed->s->sizeof_rel : bed->s->sizeof_rela)) + return FALSE; + + /* 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) + (_("%B: invalid link %lu for reloc section %s (index %u)"), + abfd, hdr->sh_link, name, shindex)); + return _bfd_elf_make_section_from_shdr (abfd, hdr, name, + shindex); + } + + /* 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 + || elf_elfsections (abfd)[hdr->sh_link]->sh_type == SHT_DYNSYM) + && ! 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, an invalid section, or another reloc section. */ + if (hdr->sh_link != elf_onesymtab (abfd) + || hdr->sh_info == SHN_UNDEF + || (hdr->sh_info >= SHN_LORESERVE && hdr->sh_info <= SHN_HIRESERVE) + || hdr->sh_info >= num_sec + || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_REL + || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELA) + return _bfd_elf_make_section_from_shdr (abfd, hdr, name, + shindex); + + 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 = 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, shindex); + break; + + case SHT_GNU_versym: + if (hdr->sh_entsize != sizeof (Elf_External_Versym)) + return FALSE; + elf_dynversym (abfd) = shindex; + elf_tdata (abfd)->dynversym_hdr = *hdr; + return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + 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, shindex); + 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. */ + if (hdr->sh_entsize != GRP_ENTRY_SIZE) + return FALSE; + name = group_signature (abfd, hdr); + if (name == NULL) + return FALSE; + if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) + 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; + + /* We try to keep the same section order as it comes in. */ + idx += n_elt; + 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. */ + return bed->elf_backend_section_from_shdr (abfd, hdr, name, + shindex); + } + + 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 (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_UNDEF && 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 (bfd *abfd, unsigned int index) +{ + if (index >= elf_numsections (abfd)) + return NULL; + return elf_elfsections (abfd)[index]->bfd_section; +} + +static const struct bfd_elf_special_section special_sections_b[] = +{ + { ".bss", 4, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_c[] = +{ + { ".comment", 8, 0, SHT_PROGBITS, 0 }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_d[] = +{ + { ".data", 5, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { ".data1", 6, 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { ".debug", 6, 0, SHT_PROGBITS, 0 }, + { ".debug_line", 11, 0, SHT_PROGBITS, 0 }, + { ".debug_info", 11, 0, SHT_PROGBITS, 0 }, + { ".debug_abbrev", 13, 0, SHT_PROGBITS, 0 }, + { ".debug_aranges", 14, 0, SHT_PROGBITS, 0 }, + { ".dynamic", 8, 0, SHT_DYNAMIC, SHF_ALLOC }, + { ".dynstr", 7, 0, SHT_STRTAB, SHF_ALLOC }, + { ".dynsym", 7, 0, SHT_DYNSYM, SHF_ALLOC }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_f[] = +{ + { ".fini", 5, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + { ".fini_array", 11, 0, SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_g[] = +{ + { ".gnu.linkonce.b",15, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, + { ".got", 4, 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { ".gnu.version", 12, 0, SHT_GNU_versym, 0 }, + { ".gnu.version_d", 14, 0, SHT_GNU_verdef, 0 }, + { ".gnu.version_r", 14, 0, SHT_GNU_verneed, 0 }, + { ".gnu.liblist", 12, 0, SHT_GNU_LIBLIST, SHF_ALLOC }, + { ".gnu.conflict", 13, 0, SHT_RELA, SHF_ALLOC }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_h[] = +{ + { ".hash", 5, 0, SHT_HASH, SHF_ALLOC }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_i[] = +{ + { ".init", 5, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + { ".init_array", 11, 0, SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE }, + { ".interp", 7, 0, SHT_PROGBITS, 0 }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_l[] = +{ + { ".line", 5, 0, SHT_PROGBITS, 0 }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_n[] = +{ + { ".note.GNU-stack",15, 0, SHT_PROGBITS, 0 }, + { ".note", 5, -1, SHT_NOTE, 0 }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_p[] = +{ + { ".preinit_array", 14, 0, SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE }, + { ".plt", 4, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_r[] = +{ + { ".rodata", 7, -2, SHT_PROGBITS, SHF_ALLOC }, + { ".rodata1", 8, 0, SHT_PROGBITS, SHF_ALLOC }, + { ".rela", 5, -1, SHT_RELA, 0 }, + { ".rel", 4, -1, SHT_REL, 0 }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_s[] = +{ + { ".shstrtab", 9, 0, SHT_STRTAB, 0 }, + { ".strtab", 7, 0, SHT_STRTAB, 0 }, + { ".symtab", 7, 0, SHT_SYMTAB, 0 }, + { ".stabstr", 5, 3, SHT_STRTAB, 0 }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_t[] = +{ + { ".text", 5, -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + { ".tbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS }, + { ".tdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section *special_sections[] = +{ + special_sections_b, /* 'b' */ + special_sections_c, /* 'b' */ + special_sections_d, /* 'd' */ + NULL, /* 'e' */ + special_sections_f, /* 'f' */ + special_sections_g, /* 'g' */ + special_sections_h, /* 'h' */ + special_sections_i, /* 'i' */ + NULL, /* 'j' */ + NULL, /* 'k' */ + special_sections_l, /* 'l' */ + NULL, /* 'm' */ + special_sections_n, /* 'n' */ + NULL, /* 'o' */ + special_sections_p, /* 'p' */ + NULL, /* 'q' */ + special_sections_r, /* 'r' */ + special_sections_s, /* 's' */ + special_sections_t, /* 't' */ +}; + +const struct bfd_elf_special_section * +_bfd_elf_get_special_section (const char *name, + const struct bfd_elf_special_section *spec, + unsigned int rela) +{ + int i; + int len; + + len = strlen (name); + + for (i = 0; spec[i].prefix != NULL; i++) + { + int suffix_len; + int prefix_len = spec[i].prefix_length; + + if (len < prefix_len) + continue; + if (memcmp (name, spec[i].prefix, prefix_len) != 0) + continue; + + suffix_len = spec[i].suffix_length; + if (suffix_len <= 0) + { + if (name[prefix_len] != 0) + { + if (suffix_len == 0) + continue; + if (name[prefix_len] != '.' + && (suffix_len == -2 + || (rela && spec[i].type == SHT_REL))) + continue; + } + } + else + { + if (len < prefix_len + suffix_len) + continue; + if (memcmp (name + len - suffix_len, + spec[i].prefix + prefix_len, + suffix_len) != 0) + continue; + } + return &spec[i]; + } + + return NULL; +} + +const struct bfd_elf_special_section * +_bfd_elf_get_sec_type_attr (bfd *abfd, asection *sec) +{ + int i; + const struct bfd_elf_special_section *spec; + const struct elf_backend_data *bed; + + /* See if this is one of the special sections. */ + if (sec->name == NULL) + return NULL; + + bed = get_elf_backend_data (abfd); + spec = bed->special_sections; + if (spec) + { + spec = _bfd_elf_get_special_section (sec->name, + bed->special_sections, + sec->use_rela_p); + if (spec != NULL) + return spec; + } + + if (sec->name[0] != '.') + return NULL; + + i = sec->name[1] - 'b'; + if (i < 0 || i > 't' - 'b') + return NULL; + + spec = special_sections[i]; + + if (spec == NULL) + return NULL; + + return _bfd_elf_get_special_section (sec->name, spec, sec->use_rela_p); +} + +bfd_boolean +_bfd_elf_new_section_hook (bfd *abfd, asection *sec) +{ + struct bfd_elf_section_data *sdata; + const struct elf_backend_data *bed; + const struct bfd_elf_special_section *ssect; + + sdata = (struct bfd_elf_section_data *) sec->used_by_bfd; + if (sdata == NULL) + { + sdata = bfd_zalloc (abfd, sizeof (*sdata)); + if (sdata == NULL) + return FALSE; + sec->used_by_bfd = sdata; + } + + /* Indicate whether or not this section should use RELA relocations. */ + bed = get_elf_backend_data (abfd); + sec->use_rela_p = bed->default_use_rela_p; + + /* When we read a file, we don't need section type and flags unless + it is a linker created section. They will be overridden in + _bfd_elf_make_section_from_shdr anyway. */ + if (abfd->direction != read_direction + || (sec->flags & SEC_LINKER_CREATED) != 0) + { + ssect = (*bed->get_sec_type_attr) (abfd, sec); + if (ssect != NULL) + { + elf_section_type (sec) = ssect->type; + elf_section_flags (sec) = ssect->attr; + } + } + + 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 (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, 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->size = hdr->p_filesz; + newsect->filepos = hdr->p_offset; + newsect->flags |= SEC_HAS_CONTENTS; + newsect->alignment_power = bfd_log2 (hdr->p_align); + 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, 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->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 (bfd *abfd, Elf_Internal_Phdr *hdr, int index) +{ + const 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, 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"); + + case PT_GNU_STACK: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "stack"); + + case PT_GNU_RELRO: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "relro"); + + default: + /* Check for any processor-specific program segment types. */ + bed = get_elf_backend_data (abfd); + return bed->elf_backend_section_from_phdr (abfd, hdr, index, "proc"); + } +} + +/* 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 (bfd *abfd, + Elf_Internal_Shdr *rel_hdr, + asection *asect, + bfd_boolean use_rela_p) +{ + char *name; + const 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 = 1 << bed->s->log_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 (bfd *abfd, asection *asect, void *failedptrarg) +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + bfd_boolean *failedptr = 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; + } + + /* Don't clear sh_flags. Assembler may set additional bits. */ + + 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->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; + + /* If the section type is unspecified, we set it based on + asect->flags. */ + if (this_hdr->sh_type == SHT_NULL) + { + if ((asect->flags & SEC_GROUP) != 0) + this_hdr->sh_type = SHT_GROUP; + 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; + } + + switch (this_hdr->sh_type) + { + default: + break; + + case SHT_STRTAB: + case SHT_INIT_ARRAY: + case SHT_FINI_ARRAY: + case SHT_PREINIT_ARRAY: + case SHT_NOTE: + case SHT_NOBITS: + case SHT_PROGBITS: + break; + + case SHT_HASH: + this_hdr->sh_entsize = bed->s->sizeof_hash_entry; + break; + + case SHT_DYNSYM: + this_hdr->sh_entsize = bed->s->sizeof_sym; + break; + + case SHT_DYNAMIC: + this_hdr->sh_entsize = bed->s->sizeof_dyn; + break; + + case SHT_RELA: + if (get_elf_backend_data (abfd)->may_use_rela_p) + this_hdr->sh_entsize = bed->s->sizeof_rela; + break; + + case SHT_REL: + if (get_elf_backend_data (abfd)->may_use_rel_p) + this_hdr->sh_entsize = bed->s->sizeof_rel; + break; + + case SHT_GNU_versym: + this_hdr->sh_entsize = sizeof (Elf_External_Versym); + break; + + case 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); + break; + + case 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); + break; + + case SHT_GROUP: + this_hdr->sh_entsize = 4; + break; + } + + 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->size == 0 + && (asect->flags & SEC_HAS_CONTENTS) == 0) + { + struct bfd_link_order *o = asect->map_tail.link_order; + + this_hdr->sh_size = 0; + if (o != NULL) + { + this_hdr->sh_size = o->offset + o->size; + if (this_hdr->sh_size != 0) + 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 (bfd *abfd, asection *sec, void *failedptrarg) +{ + bfd_boolean *failedptr = failedptrarg; + unsigned long symindx; + asection *elt, *first; + unsigned char *loc; + bfd_boolean gas; + + /* Ignore linker created group section. See elfNN_ia64_object_p in + elfxx-ia64.c. */ + if (((sec->flags & (SEC_GROUP | SEC_LINKER_CREATED)) != SEC_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->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->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 ((loc -= 4) != 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 (bfd *abfd, struct bfd_link_info *link_info) +{ + struct elf_obj_tdata *t = elf_tdata (abfd); + asection *sec; + unsigned int section_number, secn; + Elf_Internal_Shdr **i_shdrp; + struct bfd_elf_section_data *d; + + section_number = 1; + + _bfd_elf_strtab_clear_all_refs (elf_shstrtab (abfd)); + + /* SHT_GROUP sections are in relocatable files only. */ + if (link_info == NULL || link_info->relocatable) + { + /* Put SHT_GROUP sections first. */ + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + d = elf_section_data (sec); + + if (d->this_hdr.sh_type == SHT_GROUP) + { + if (sec->flags & SEC_LINKER_CREATED) + { + /* Remove the linker created SHT_GROUP sections. */ + bfd_section_list_remove (abfd, sec); + abfd->section_count--; + } + else + { + if (section_number == SHN_LORESERVE) + section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE; + d->this_idx = section_number++; + } + } + } + } + + for (sec = abfd->sections; sec; sec = sec->next) + { + d = elf_section_data (sec); + + if (d->this_hdr.sh_type != SHT_GROUP) + { + 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. */ + i_shdrp = bfd_zalloc2 (abfd, section_number, sizeof (Elf_Internal_Shdr *)); + if (i_shdrp == NULL) + return FALSE; + + i_shdrp[0] = bfd_zalloc (abfd, sizeof (Elf_Internal_Shdr)); + 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; + } + + /* We need to set up sh_link for SHF_LINK_ORDER. */ + if ((d->this_hdr.sh_flags & SHF_LINK_ORDER) != 0) + { + s = elf_linked_to_section (sec); + if (s) + { + /* elf_linked_to_section points to the input section. */ + if (link_info != NULL) + { + /* Check discarded linkonce section. */ + if (elf_discarded_section (s)) + { + asection *kept; + (*_bfd_error_handler) + (_("%B: sh_link of section `%A' points to discarded section `%A' of `%B'"), + abfd, d->this_hdr.bfd_section, + s, s->owner); + /* Point to the kept section if it has the same + size as the discarded one. */ + kept = _bfd_elf_check_kept_section (s); + if (kept == NULL) + { + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + s = kept; + } + + s = s->output_section; + BFD_ASSERT (s != NULL); + } + else + { + /* Handle objcopy. */ + if (s->output_section == NULL) + { + (*_bfd_error_handler) + (_("%B: sh_link of section `%A' points to removed section `%A' of `%B'"), + abfd, d->this_hdr.bfd_section, s, s->owner); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + s = s->output_section; + } + d->this_hdr.sh_link = elf_section_data (s)->this_idx; + } + else + { + /* PR 290: + The Intel C compiler generates SHT_IA_64_UNWIND with + SHF_LINK_ORDER. But it doesn't set the sh_link or + sh_info fields. Hence we could get the situation + where s is NULL. */ + const struct elf_backend_data *bed + = get_elf_backend_data (abfd); + if (bed->link_order_error_handler) + bed->link_order_error_handler + (_("%B: warning: sh_link not set for section `%A'"), + abfd, sec); + } + } + + 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 = bfd_malloc (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_GNU_LIBLIST: + /* sh_link is the section header index of the prelink library + list + used for the dynamic entries, or the symbol table, or the + version strings. */ + s = bfd_get_section_by_name (abfd, (sec->flags & SEC_ALLOC) + ? ".dynstr" : ".gnu.libstr"); + 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 int +sym_is_global (bfd *abfd, asymbol *sym) +{ + /* If the backend has a special mapping, use it. */ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + if (bed->elf_backend_sym_is_global) + return (*bed->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 (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; + +#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++; + sect_syms = bfd_zalloc2 (abfd, max_index, sizeof (asymbol *)); + 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. */ + new_syms = bfd_alloc2 (abfd, num_locals + num_globals, sizeof (asymbol *)); + + 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 (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. */ + +file_ptr +_bfd_elf_assign_file_position_for_section (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 (bfd *abfd, + struct bfd_link_info *link_info) +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + bfd_boolean failed; + struct bfd_strtab_hash *strtab = NULL; + 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, link_info)) + 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, link_info)) + 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 struct elf_segment_map * +make_mapping (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 = 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; +} + +/* Create the PT_DYNAMIC segment, which includes DYNSEC. Returns NULL + on failure. */ + +struct elf_segment_map * +_bfd_elf_make_dynamic_segment (bfd *abfd, asection *dynsec) +{ + struct elf_segment_map *m; + + m = bfd_zalloc (abfd, sizeof (struct elf_segment_map)); + if (m == NULL) + return NULL; + m->next = NULL; + m->p_type = PT_DYNAMIC; + m->count = 1; + m->sections[0] = dynsec; + + return m; +} + +/* Set up a mapping from BFD sections to program segments. */ + +static bfd_boolean +map_sections_to_segments (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; + bfd_vma last_size; + 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. */ + + sections = bfd_malloc2 (bfd_count_sections (abfd), sizeof (asection *)); + 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 = 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 = 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; + last_size = 0; + 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_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 | SEC_THREAD_LOCAL)) == 0 + && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0) + { + /* We don't want to put a loadable section after a + nonloadable section in the same segment. + Consider .tbss sections as loadable for this purpose. */ + 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_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; + /* .tbss sections effectively have zero size. */ + if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL) + last_size = hdr->size; + else + last_size = 0; + 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; + /* .tbss sections effectively have zero size. */ + if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL) + last_size = hdr->size; + else + last_size = 0; + 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) + { + m = _bfd_elf_make_dynamic_segment (abfd, dynsec); + if (m == NULL) + goto error_return; + *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 = 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 = 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 = 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; + } + + if (elf_tdata (abfd)->stack_flags) + { + amt = sizeof (struct elf_segment_map); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_GNU_STACK; + m->p_flags = elf_tdata (abfd)->stack_flags; + m->p_flags_valid = 1; + + *pm = m; + pm = &m->next; + } + + if (elf_tdata (abfd)->relro) + { + amt = sizeof (struct elf_segment_map); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_GNU_RELRO; + m->p_flags = PF_R; + m->p_flags_valid = 1; + + *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 (const void *arg1, const void *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->size : 0; + size2 = (sec2->flags & SEC_LOAD) ? sec2->size : 0; + + if (size1 < size2) + return -1; + if (size1 > size2) + return 1; + + return sec1->target_index - sec2->target_index; +} + +/* Ian Lance Taylor writes: + + We shouldn't be using % with a negative signed number. That's just + not good. We have to make sure either that the number is not + negative, or that the number has an unsigned type. When the types + are all the same size they wind up as unsigned. When file_ptr is a + larger signed type, the arithmetic winds up as signed long long, + which is wrong. + + What we're trying to say here is something like ``increase OFF by + the least amount that will cause it to be equal to the VMA modulo + the page size.'' */ +/* In other words, something like: + + vma_offset = m->sections[0]->vma % bed->maxpagesize; + off_offset = off % bed->maxpagesize; + if (vma_offset < off_offset) + adjustment = vma_offset + bed->maxpagesize - off_offset; + else + adjustment = vma_offset - off_offset; + + which can can be collapsed into the expression below. */ + +static file_ptr +vma_page_aligned_bias (bfd_vma vma, ufile_ptr off, bfd_vma maxpagesize) +{ + return ((vma - off) % maxpagesize); +} + +static void +print_segment_map (bfd *abfd) +{ + struct elf_segment_map *m; + unsigned int i, j; + + fprintf (stderr, _(" Section to Segment mapping:\n")); + fprintf (stderr, _(" Segment Sections...\n")); + + for (i= 0, m = elf_tdata (abfd)->segment_map; + m != NULL; + i++, m = m->next) + { + const char *pt = get_segment_type (m->p_type); + char buf[32]; + + if (pt == NULL) + { + if (m->p_type >= PT_LOPROC && m->p_type <= PT_HIPROC) + sprintf (buf, "LOPROC+%7.7x", + (unsigned int) (m->p_type - PT_LOPROC)); + else if (m->p_type >= PT_LOOS && m->p_type <= PT_HIOS) + sprintf (buf, "LOOS+%7.7x", + (unsigned int) (m->p_type - PT_LOOS)); + else + snprintf (buf, sizeof (buf), "%8.8x", + (unsigned int) m->p_type); + pt = buf; + } + fprintf (stderr, " %2.2d: %14.14s: ", i, pt); + for (j = 0; j < m->count; j++) + fprintf (stderr, "%s ", m->sections [j]->name); + putc ('\n',stderr); + } +} + +/* 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 (bfd *abfd, struct bfd_link_info *link_info) +{ + 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; + + 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. We also remove excluded + sections. */ + for (m = elf_tdata (abfd)->segment_map; + m != NULL; + m = m->next) + { + unsigned int new_count; + unsigned int i; + + new_count = 0; + for (i = 0; i < m->count; i ++) + { + if ((m->sections[i]->flags & SEC_EXCLUDE) == 0 + && ((m->sections[i]->flags & SEC_ALLOC) != 0 + || m->p_type != PT_LOAD)) + { + 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, link_info)) + 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) + { + elf_tdata (abfd)->next_file_pos = bed->s->sizeof_ehdr; + 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) + (_("%B: Not enough room for program headers (allocated %u, need %u)"), + abfd, alloc, count)); + print_segment_map (abfd); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + if (alloc == 0) + alloc = count; + + phdrs = bfd_alloc2 (abfd, alloc, sizeof (Elf_Internal_Phdr)); + 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); + + /* An ELF segment (described by Elf_Internal_Phdr) may contain a + number of sections with contents contributing to both p_filesz + and p_memsz, followed by a number of sections with no contents + that just contribute to p_memsz. In this loop, OFF tracks next + available file offset for PT_LOAD and PT_NOTE segments. VOFF is + an adjustment we use for segments that have no file contents + but need zero filled memory allocation. */ + voff = 0; + p->p_type = m->p_type; + p->p_flags = m->p_flags; + + if (p->p_type == PT_LOAD + && m->count > 0) + { + bfd_size_type align; + bfd_vma adjust; + unsigned int align_power = 0; + + for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) + { + unsigned int secalign; + + secalign = bfd_get_section_alignment (abfd, *secpp); + if (secalign > align_power) + align_power = secalign; + } + align = (bfd_size_type) 1 << align_power; + + if ((abfd->flags & D_PAGED) != 0 && bed->maxpagesize > align) + align = bed->maxpagesize; + + adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align); + off += adjust; + if (adjust != 0 + && !m->includes_filehdr + && !m->includes_phdrs + && (ufile_ptr) off >= align) + { + /* If the first section isn't loadable, the same holds for + any other sections. Since the segment won't need file + space, we can make p_offset overlap some prior segment. + However, .tbss is special. If a segment starts with + .tbss, we need to look at the next section to decide + whether the segment has any loadable sections. */ + i = 0; + while ((m->sections[i]->flags & SEC_LOAD) == 0) + { + if ((m->sections[i]->flags & SEC_THREAD_LOCAL) == 0 + || ++i >= m->count) + { + off -= adjust; + voff = adjust - align; + break; + } + } + } + } + /* Make sure the .dynamic section is the first section in the + PT_DYNAMIC segment. */ + else if (p->p_type == PT_DYNAMIC + && m->count > 1 + && strcmp (m->sections[0]->name, ".dynamic") != 0) + { + _bfd_error_handler + (_("%B: The first section in the PT_DYNAMIC segment is not the .dynamic section"), + abfd); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + 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 = 1 << bed->s->log_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) + (_("%B: Not enough room for program headers, try linking with -N"), + 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 + voff; + else + { + file_ptr adjust; + + adjust = off - (p->p_offset + p->p_filesz); + p->p_filesz += adjust; + p->p_memsz += adjust; + } + } + + 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); + + if (p->p_type == PT_LOAD + || p->p_type == PT_TLS) + { + bfd_signed_vma adjust; + + if ((flags & SEC_LOAD) != 0) + { + adjust = sec->lma - (p->p_paddr + p->p_filesz); + if (adjust < 0) + { + (*_bfd_error_handler) + (_("%B: section %A lma 0x%lx overlaps previous sections"), + abfd, sec, (unsigned long) sec->lma); + adjust = 0; + } + off += adjust; + p->p_filesz += adjust; + p->p_memsz += adjust; + } + /* .tbss is special. It doesn't contribute to p_memsz of + normal segments. */ + else if ((flags & SEC_THREAD_LOCAL) == 0 + || p->p_type == PT_TLS) + { + /* The section VMA must equal the file position + modulo the page size. */ + bfd_size_type page = align; + if ((abfd->flags & D_PAGED) != 0 && bed->maxpagesize > page) + page = bed->maxpagesize; + adjust = vma_page_aligned_bias (sec->vma, + p->p_vaddr + p->p_memsz, + page); + p->p_memsz += adjust; + } + } + + if (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core) + { + /* The section at i == 0 is the one that actually contains + everything. */ + if (i == 0) + { + sec->filepos = off; + off += sec->size; + p->p_filesz = sec->size; + p->p_memsz = 0; + p->p_align = 1; + } + else + { + /* The rest are fake sections that shouldn't be written. */ + sec->filepos = 0; + sec->size = 0; + sec->flags = 0; + continue; + } + } + else + { + if (p->p_type == PT_LOAD) + { + sec->filepos = off; + /* FIXME: The SEC_HAS_CONTENTS test here dates back to + 1997, and the exact reason for it isn't clear. One + plausible explanation is that it is to work around + a problem we have with linker scripts using data + statements in NOLOAD sections. I don't think it + makes a great deal of sense to have such a section + assigned to a PT_LOAD segment, but apparently + people do this. The data statement results in a + bfd_data_link_order being built, and these need + section contents to write into. Eventually, we get + to _bfd_elf_write_object_contents which writes any + section with contents to the output. Make room + here for the write, so that following segments are + not trashed. */ + if ((flags & SEC_LOAD) != 0 + || (flags & SEC_HAS_CONTENTS) != 0) + off += sec->size; + } + + if ((flags & SEC_LOAD) != 0) + { + p->p_filesz += sec->size; + p->p_memsz += sec->size; + } + /* PR ld/594: Sections in note segments which are not loaded + contribute to the file size but not the in-memory size. */ + else if (p->p_type == PT_NOTE + && (flags & SEC_HAS_CONTENTS) != 0) + p->p_filesz += sec->size; + + /* .tbss is special. It doesn't contribute to p_memsz of + normal segments. */ + else if ((flags & SEC_THREAD_LOCAL) == 0 + || p->p_type == PT_TLS) + p->p_memsz += sec->size; + + if (p->p_type == PT_TLS + && sec->size == 0 + && (sec->flags & SEC_HAS_CONTENTS) == 0) + { + struct bfd_link_order *o = sec->map_tail.link_order; + if (o != NULL) + p->p_memsz += o->offset + o->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); + /* If the section has not yet been assigned a file position, + do so now. The ARM BPABI requires that .dynamic section + not be marked SEC_ALLOC because it is not part of any + PT_LOAD segment, so it will not be processed above. */ + if (p->p_type == PT_DYNAMIC && m->sections[0]->filepos == 0) + { + unsigned int i; + Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd); + + i = 1; + while (i_shdrpp[i]->bfd_section != m->sections[0]) + ++i; + off = (_bfd_elf_assign_file_position_for_section + (i_shdrpp[i], off, TRUE)); + p->p_filesz = m->sections[0]->size; + } + 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; + } + else if (p->p_type == PT_GNU_RELRO) + { + Elf_Internal_Phdr *lp; + + for (lp = phdrs; lp < phdrs + count; ++lp) + { + if (lp->p_type == PT_LOAD + && lp->p_vaddr <= link_info->relro_end + && lp->p_vaddr >= link_info->relro_start + && lp->p_vaddr + lp->p_filesz + >= link_info->relro_end) + break; + } + + if (lp < phdrs + count + && link_info->relro_end > lp->p_vaddr) + { + p->p_vaddr = lp->p_vaddr; + p->p_paddr = lp->p_paddr; + p->p_offset = lp->p_offset; + p->p_filesz = link_info->relro_end - lp->p_vaddr; + p->p_memsz = p->p_filesz; + p->p_align = 1; + p->p_flags = (lp->p_flags & ~PF_W); + } + else + { + memset (p, 0, sizeof *p); + p->p_type = PT_NULL; + } + } + } + } + + /* 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 (bfd *abfd) +{ + size_t segs; + asection *s; + const 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; + } + + if (elf_tdata (abfd)->stack_flags) + { + /* We need a PT_GNU_STACK segment. */ + ++segs; + } + + if (elf_tdata (abfd)->relro) + { + /* We need a PT_GNU_RELRO 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. + + Reloc sections come in two flavours: Those processed specially as + "side-channel" data attached to a section to which they apply, and + those that bfd doesn't process as relocations. The latter sort are + stored in a normal bfd section by bfd_section_from_shdr. We don't + consider the former sort here, unless they form part of the loadable + image. Reloc sections not assigned here will be handled later by + assign_file_positions_for_relocs. + + We also don't set the positions of the .symtab and .strtab here. */ + +static bfd_boolean +assign_file_positions_except_relocs (bfd *abfd, + struct bfd_link_info *link_info) +{ + 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; + const 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) + && hdr->bfd_section == NULL) + || 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, link_info)) + 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) + (_("%B: warning: allocated section `%s' not in segment"), + abfd, + (hdr->bfd_section == NULL + ? "*unknown*" + : hdr->bfd_section->name))); + if ((abfd->flags & D_PAGED) != 0) + off += vma_page_aligned_bias (hdr->sh_addr, off, + bed->maxpagesize); + else + off += vma_page_aligned_bias (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->bfd_section == NULL) + || 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, 1 << bed->s->log_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 (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; + const 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: + i_ehdrp->e_machine = bed->elf_machine_code; + } + + 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. */ + ; + 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 (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 (bfd *abfd) +{ + const 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, 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 (elf_shstrtab (abfd) != NULL + && (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 (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 (bfd *abfd, struct bfd_section *asect) +{ + const 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 + 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 (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) + (_("%B: symbol `%s' required but not present"), + 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; +} + +/* Rewrite program header information. */ + +static bfd_boolean +rewrite_elf_program_header (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; + const struct elf_backend_data *bed; + + 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->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->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->size > 0 \ + && (bfd_vma) s->filepos >= p->p_offset \ + && ((bfd_vma) s->filepos + s->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_GNU_STACK segments do not include any sections. + 6. PT_TLS segment includes only SHF_TLS sections. + 7. SHF_TLS sections are only in PT_TLS or PT_LOAD segments. + 8. PT_DYNAMIC should not contain empty sections at the beginning + (with the possible exception of .dynamic). */ +#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_GNU_STACK \ + && (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) \ + && (segment->p_type != PT_DYNAMIC \ + || SECTION_SIZE (section, segment) > 0 \ + || (segment->p_paddr \ + ? segment->p_paddr != section->lma \ + : segment->p_vaddr != section->vma) \ + || (strcmp (bfd_get_section_name (ibfd, section), ".dynamic") \ + == 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 + assignment 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 = 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) + (_("%B: warning: Empty loadable segment detected, is this intentional ?\n"), + 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. */ + sections = bfd_malloc2 (section_count, sizeof (asection *)); + 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->size, + maxpagesize) + < BFD_ALIGN (output_section->lma, maxpagesize)) + || ((prev_sec->lma + prev_sec->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 = 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; + } + +#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 ELF program header information. */ + +static bfd_boolean +copy_elf_program_header (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; + unsigned int i; + unsigned int num_segments; + bfd_boolean phdr_included = FALSE; + + iehdr = elf_elfheader (ibfd); + + map_first = NULL; + pointer_to_map = &map_first; + + num_segments = elf_elfheader (ibfd)->e_phnum; + for (i = 0, segment = elf_tdata (ibfd)->phdr; + i < num_segments; + i++, segment++) + { + asection *section; + unsigned int section_count; + bfd_size_type amt; + Elf_Internal_Shdr *this_hdr; + + /* FIXME: Do we need to copy PT_NULL segment? */ + if (segment->p_type == PT_NULL) + continue; + + /* Compute how many sections are in this segment. */ + for (section = ibfd->sections, section_count = 0; + section != NULL; + section = section->next) + { + this_hdr = &(elf_section_data(section)->this_hdr); + if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment)) + section_count++; + } + + /* Allocate a segment map big enough to contain + all of the sections we have selected. */ + amt = sizeof (struct elf_segment_map); + if (section_count != 0) + amt += ((bfd_size_type) section_count - 1) * sizeof (asection *); + map = bfd_alloc (obfd, amt); + if (map == NULL) + return FALSE; + + /* Initialize the fields of the output segment map with the + input segment. */ + 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) + { + unsigned int isec = 0; + + for (section = ibfd->sections; + section != NULL; + section = section->next) + { + this_hdr = &(elf_section_data(section)->this_hdr); + if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment)) + map->sections[isec++] = section->output_section; + } + } + + map->count = section_count; + *pointer_to_map = map; + pointer_to_map = &map->next; + } + + elf_tdata (obfd)->segment_map = map_first; + return TRUE; +} + +/* Copy private BFD data. This copies or rewrites ELF program header + information. */ + +static bfd_boolean +copy_private_bfd_data (bfd *ibfd, bfd *obfd) +{ + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return TRUE; + + if (elf_tdata (ibfd)->phdr == NULL) + return TRUE; + + if (ibfd->xvec == obfd->xvec) + { + /* Check if any sections in the input BFD covered by ELF program + header are changed. */ + Elf_Internal_Phdr *segment; + asection *section, *osec; + unsigned int i, num_segments; + Elf_Internal_Shdr *this_hdr; + + /* Initialize the segment mark field. */ + for (section = obfd->sections; section != NULL; + section = section->next) + section->segment_mark = FALSE; + + num_segments = elf_elfheader (ibfd)->e_phnum; + for (i = 0, segment = elf_tdata (ibfd)->phdr; + i < num_segments; + i++, segment++) + { + for (section = ibfd->sections; + section != NULL; section = section->next) + { + /* We mark the output section so that we know it comes + from the input BFD. */ + osec = section->output_section; + if (osec) + osec->segment_mark = TRUE; + + /* Check if this section is covered by the segment. */ + this_hdr = &(elf_section_data(section)->this_hdr); + if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment)) + { + /* FIXME: Check if its output section is changed or + removed. What else do we need to check? */ + if (osec == NULL + || section->flags != osec->flags + || section->lma != osec->lma + || section->vma != osec->vma + || section->size != osec->size + || section->rawsize != osec->rawsize + || section->alignment_power != osec->alignment_power) + goto rewrite; + } + } + } + + /* Check to see if any output section doesn't come from the + input BFD. */ + for (section = obfd->sections; section != NULL; + section = section->next) + { + if (section->segment_mark == FALSE) + goto rewrite; + else + section->segment_mark = FALSE; + } + + return copy_elf_program_header (ibfd, obfd); + } + +rewrite: + return rewrite_elf_program_header (ibfd, obfd); +} + +/* Initialize private output section information from input section. */ + +bfd_boolean +_bfd_elf_init_private_section_data (bfd *ibfd, + asection *isec, + bfd *obfd, + asection *osec, + struct bfd_link_info *link_info) + +{ + Elf_Internal_Shdr *ihdr, *ohdr; + bfd_boolean need_group = link_info == NULL || link_info->relocatable; + + if (ibfd->xvec->flavour != bfd_target_elf_flavour + || obfd->xvec->flavour != bfd_target_elf_flavour) + return TRUE; + + /* FIXME: What if the output ELF section type has been set to + something different? */ + if (elf_section_type (osec) == SHT_NULL) + elf_section_type (osec) = elf_section_type (isec); + + /* Set things up for objcopy and relocatable link. The output + SHT_GROUP section will have its elf_next_in_group pointing back + to the input group members. Ignore linker created group section. + See elfNN_ia64_object_p in elfxx-ia64.c. */ + + if (need_group) + { + if (elf_sec_group (isec) == NULL + || (elf_sec_group (isec)->flags & SEC_LINKER_CREATED) == 0) + { + if (elf_section_flags (isec) & SHF_GROUP) + elf_section_flags (osec) |= SHF_GROUP; + elf_next_in_group (osec) = elf_next_in_group (isec); + elf_group_name (osec) = elf_group_name (isec); + } + } + + ihdr = &elf_section_data (isec)->this_hdr; + + /* We need to handle elf_linked_to_section for SHF_LINK_ORDER. We + don't use the output section of the linked-to section since it + may be NULL at this point. */ + if ((ihdr->sh_flags & SHF_LINK_ORDER) != 0) + { + ohdr = &elf_section_data (osec)->this_hdr; + ohdr->sh_flags |= SHF_LINK_ORDER; + elf_linked_to_section (osec) = elf_linked_to_section (isec); + } + + osec->use_rela_p = isec->use_rela_p; + + 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 (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; + + 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; + + return _bfd_elf_init_private_section_data (ibfd, isec, obfd, osec, + NULL); +} + +/* Copy private header information. */ + +bfd_boolean +_bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd) +{ + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return TRUE; + + /* Copy over private BFD data if it has not already been copied. + This must be done here, rather than in the copy_private_bfd_data + entry point, because the latter is called after the section + contents have been set, which means that the program headers have + already been worked out. */ + if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL) + { + if (! copy_private_bfd_data (ibfd, obfd)) + return FALSE; + } + + 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 (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 (bfd *abfd, + struct bfd_strtab_hash **sttp, + int relocatable_p) +{ + const 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; + bfd_byte *outbound_syms; + bfd_byte *outbound_shndx; + int idx; + bfd_size_type amt; + bfd_boolean name_local_sections; + + 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 = 1 << bed->s->log_file_align; + + symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; + symstrtab_hdr->sh_type = SHT_STRTAB; + + outbound_syms = bfd_alloc2 (abfd, 1 + symcount, bed->s->sizeof_sym); + if (outbound_syms == NULL) + { + _bfd_stringtab_free (stt); + return FALSE; + } + symtab_hdr->contents = 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_zalloc2 (abfd, 1 + symcount, + sizeof (Elf_External_Sym_Shndx)); + 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); + } + + name_local_sections + = (bed->elf_backend_name_local_section_symbols + && bed->elf_backend_name_local_section_symbols (abfd)); + + 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 (!name_local_sections + && (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 (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 (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 (bfd *abfd ATTRIBUTE_UNUSED, + sec_ptr asect) +{ + return (asect->reloc_count + 1) * sizeof (arelent *); +} + +/* Canonicalize the relocs. */ + +long +_bfd_elf_canonicalize_reloc (bfd *abfd, + sec_ptr section, + arelent **relptr, + asymbol **symbols) +{ + arelent *tblptr; + unsigned int i; + const 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_canonicalize_symtab (bfd *abfd, asymbol **allocation) +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + long symcount = bed->s->slurp_symbol_table (abfd, allocation, FALSE); + + if (symcount >= 0) + bfd_get_symcount (abfd) = symcount; + return symcount; +} + +long +_bfd_elf_canonicalize_dynamic_symtab (bfd *abfd, + asymbol **allocation) +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + long symcount = bed->s->slurp_symbol_table (abfd, allocation, TRUE); + + if (symcount >= 0) + bfd_get_dynamic_symcount (abfd) = symcount; + return symcount; +} + +/* Return the size required for the dynamic reloc entries. Any loadable + 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 (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 ((s->flags & SEC_LOAD) != 0 + && 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->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 loadable 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 (bfd *abfd, + arelent **storage, + asymbol **syms) +{ + bfd_boolean (*slurp_relocs) (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 ((s->flags & SEC_LOAD) != 0 + && 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->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 (bfd *abfd, bfd_boolean default_imported_symver) +{ + bfd_byte *contents = NULL; + unsigned int freeidx = 0; + + if (elf_dynverref (abfd) != 0) + { + Elf_Internal_Shdr *hdr; + Elf_External_Verneed *everneed; + Elf_Internal_Verneed *iverneed; + unsigned int i; + bfd_byte *contents_end; + + hdr = &elf_tdata (abfd)->dynverref_hdr; + + elf_tdata (abfd)->verref = bfd_zalloc2 (abfd, hdr->sh_info, + sizeof (Elf_Internal_Verneed)); + if (elf_tdata (abfd)->verref == NULL) + goto error_return; + + elf_tdata (abfd)->cverrefs = hdr->sh_info; + + contents = bfd_malloc (hdr->sh_size); + if (contents == NULL) + { +error_return_verref: + elf_tdata (abfd)->verref = NULL; + elf_tdata (abfd)->cverrefs = 0; + goto error_return; + } + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 + || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size) + goto error_return_verref; + + if (hdr->sh_info && hdr->sh_size < sizeof (Elf_External_Verneed)) + goto error_return_verref; + + BFD_ASSERT (sizeof (Elf_External_Verneed) + == sizeof (Elf_External_Vernaux)); + contents_end = contents + hdr->sh_size - sizeof (Elf_External_Verneed); + 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_verref; + + if (iverneed->vn_cnt == 0) + iverneed->vn_auxptr = NULL; + else + { + iverneed->vn_auxptr = bfd_alloc2 (abfd, iverneed->vn_cnt, + sizeof (Elf_Internal_Vernaux)); + if (iverneed->vn_auxptr == NULL) + goto error_return_verref; + } + + if (iverneed->vn_aux + > (size_t) (contents_end - (bfd_byte *) everneed)) + goto error_return_verref; + + 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_verref; + + if (j + 1 < iverneed->vn_cnt) + ivernaux->vna_nextptr = ivernaux + 1; + else + ivernaux->vna_nextptr = NULL; + + if (ivernaux->vna_next + > (size_t) (contents_end - (bfd_byte *) evernaux)) + goto error_return_verref; + + evernaux = ((Elf_External_Vernaux *) + ((bfd_byte *) evernaux + ivernaux->vna_next)); + + if (ivernaux->vna_other > freeidx) + freeidx = ivernaux->vna_other; + } + + if (i + 1 < hdr->sh_info) + iverneed->vn_nextref = iverneed + 1; + else + iverneed->vn_nextref = NULL; + + if (iverneed->vn_next + > (size_t) (contents_end - (bfd_byte *) everneed)) + goto error_return_verref; + + everneed = ((Elf_External_Verneed *) + ((bfd_byte *) everneed + iverneed->vn_next)); + } + + free (contents); + contents = NULL; + } + + 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; + bfd_byte *contents_end_def, *contents_end_aux; + + hdr = &elf_tdata (abfd)->dynverdef_hdr; + + contents = bfd_malloc (hdr->sh_size); + if (contents == NULL) + goto error_return; + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 + || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size) + goto error_return; + + if (hdr->sh_info && hdr->sh_size < sizeof (Elf_External_Verdef)) + goto error_return; + + BFD_ASSERT (sizeof (Elf_External_Verdef) + >= sizeof (Elf_External_Verdaux)); + contents_end_def = contents + hdr->sh_size + - sizeof (Elf_External_Verdef); + contents_end_aux = contents + hdr->sh_size + - sizeof (Elf_External_Verdaux); + + /* 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); + + if (iverdefmem.vd_next + > (size_t) (contents_end_def - (bfd_byte *) everdef)) + goto error_return; + + everdef = ((Elf_External_Verdef *) + ((bfd_byte *) everdef + iverdefmem.vd_next)); + } + + if (default_imported_symver) + { + if (freeidx > maxidx) + maxidx = ++freeidx; + else + freeidx = ++maxidx; + } + elf_tdata (abfd)->verdef = bfd_zalloc2 (abfd, maxidx, + sizeof (Elf_Internal_Verdef)); + 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); + + if ((iverdefmem.vd_ndx & VERSYM_VERSION) == 0) + { +error_return_verdef: + elf_tdata (abfd)->verdef = NULL; + elf_tdata (abfd)->cverdefs = 0; + goto error_return; + } + + iverdef = &iverdefarr[(iverdefmem.vd_ndx & VERSYM_VERSION) - 1]; + memcpy (iverdef, &iverdefmem, sizeof (Elf_Internal_Verdef)); + + iverdef->vd_bfd = abfd; + + if (iverdef->vd_cnt == 0) + iverdef->vd_auxptr = NULL; + else + { + iverdef->vd_auxptr = bfd_alloc2 (abfd, iverdef->vd_cnt, + sizeof (Elf_Internal_Verdaux)); + if (iverdef->vd_auxptr == NULL) + goto error_return_verdef; + } + + if (iverdef->vd_aux + > (size_t) (contents_end_aux - (bfd_byte *) everdef)) + goto error_return_verdef; + + 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_verdef; + + if (j + 1 < iverdef->vd_cnt) + iverdaux->vda_nextptr = iverdaux + 1; + else + iverdaux->vda_nextptr = NULL; + + if (iverdaux->vda_next + > (size_t) (contents_end_aux - (bfd_byte *) everdaux)) + goto error_return_verdef; + + everdaux = ((Elf_External_Verdaux *) + ((bfd_byte *) everdaux + iverdaux->vda_next)); + } + + if (iverdef->vd_cnt) + iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename; + + if ((size_t) (iverdef - iverdefarr) + 1 < maxidx) + iverdef->vd_nextdef = iverdef + 1; + else + iverdef->vd_nextdef = NULL; + + everdef = ((Elf_External_Verdef *) + ((bfd_byte *) everdef + iverdef->vd_next)); + } + + free (contents); + contents = NULL; + } + else if (default_imported_symver) + { + if (freeidx < 3) + freeidx = 3; + else + freeidx++; + + elf_tdata (abfd)->verdef = bfd_zalloc2 (abfd, freeidx, + sizeof (Elf_Internal_Verdef)); + if (elf_tdata (abfd)->verdef == NULL) + goto error_return; + + elf_tdata (abfd)->cverdefs = freeidx; + } + + /* Create a default version based on the soname. */ + if (default_imported_symver) + { + Elf_Internal_Verdef *iverdef; + Elf_Internal_Verdaux *iverdaux; + + iverdef = &elf_tdata (abfd)->verdef[freeidx - 1];; + + iverdef->vd_version = VER_DEF_CURRENT; + iverdef->vd_flags = 0; + iverdef->vd_ndx = freeidx; + iverdef->vd_cnt = 1; + + iverdef->vd_bfd = abfd; + + iverdef->vd_nodename = bfd_elf_get_dt_soname (abfd); + if (iverdef->vd_nodename == NULL) + goto error_return_verdef; + iverdef->vd_nextdef = NULL; + iverdef->vd_auxptr = bfd_alloc (abfd, sizeof (Elf_Internal_Verdaux)); + if (iverdef->vd_auxptr == NULL) + goto error_return_verdef; + + iverdaux = iverdef->vd_auxptr; + iverdaux->vda_nodename = iverdef->vd_nodename; + iverdaux->vda_nextptr = NULL; + } + + return TRUE; + + error_return: + if (contents != NULL) + free (contents); + return FALSE; +} + +asymbol * +_bfd_elf_make_empty_symbol (bfd *abfd) +{ + elf_symbol_type *newsym; + bfd_size_type amt = sizeof (elf_symbol_type); + + newsym = bfd_zalloc (abfd, amt); + if (!newsym) + return NULL; + else + { + newsym->symbol.the_bfd = abfd; + return &newsym->symbol; + } +} + +void +_bfd_elf_get_symbol_info (bfd *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 (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 (bfd *abfd ATTRIBUTE_UNUSED, + asymbol *symbol ATTRIBUTE_UNUSED) +{ + abort (); + return NULL; +} + +bfd_boolean +_bfd_elf_set_arch_mach (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 (bfd *abfd ATTRIBUTE_UNUSED, + asection *section, + asymbol **symbols, + bfd_vma offset, + const char **filename_ptr, + const char **functionname_ptr) +{ + const char *filename; + asymbol *func, *file; + bfd_vma low_func; + asymbol **p; + /* ??? Given multiple file symbols, it is impossible to reliably + choose the right file name for global symbols. File symbols are + local symbols, and thus all file symbols must sort before any + global symbols. The ELF spec may be interpreted to say that a + file symbol must sort before other local symbols, but currently + ld -r doesn't do this. So, for ld -r output, it is possible to + make a better choice of file name for local symbols by ignoring + file symbols appearing after a given local symbol. */ + enum { nothing_seen, symbol_seen, file_after_symbol_seen } state; + + filename = NULL; + func = NULL; + file = NULL; + low_func = 0; + state = nothing_seen; + + for (p = symbols; *p != NULL; p++) + { + elf_symbol_type *q; + + q = (elf_symbol_type *) *p; + + switch (ELF_ST_TYPE (q->internal_elf_sym.st_info)) + { + default: + break; + case STT_FILE: + file = &q->symbol; + if (state == symbol_seen) + state = file_after_symbol_seen; + continue; + case STT_NOTYPE: + case STT_FUNC: + if (bfd_get_section (&q->symbol) == section + && q->symbol.value >= low_func + && q->symbol.value <= offset) + { + func = (asymbol *) q; + low_func = q->symbol.value; + filename = NULL; + if (file != NULL + && (ELF_ST_BIND (q->internal_elf_sym.st_info) == STB_LOCAL + || state != file_after_symbol_seen)) + filename = bfd_asymbol_name (file); + } + break; + } + if (state == nothing_seen) + state = symbol_seen; + } + + 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 (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; +} + +/* Find the line for a symbol. */ + +bfd_boolean +_bfd_elf_find_line (bfd *abfd, asymbol **symbols, asymbol *symbol, + const char **filename_ptr, unsigned int *line_ptr) +{ + return _bfd_dwarf2_find_line (abfd, symbols, symbol, + filename_ptr, line_ptr, 0, + &elf_tdata (abfd)->dwarf2_find_line_info); +} + +/* After a call to bfd_find_nearest_line, successive calls to + bfd_find_inliner_info can be used to get source information about + each level of function inlining that terminated at the address + passed to bfd_find_nearest_line. Currently this is only supported + for DWARF2 with appropriate DWARF3 extensions. */ + +bfd_boolean +_bfd_elf_find_inliner_info (bfd *abfd, + const char **filename_ptr, + const char **functionname_ptr, + unsigned int *line_ptr) +{ + bfd_boolean found; + found = _bfd_dwarf2_find_inliner_info (abfd, filename_ptr, + functionname_ptr, line_ptr, + & elf_tdata (abfd)->dwarf2_find_line_info); + return found; +} + +int +_bfd_elf_sizeof_headers (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 (bfd *abfd, + sec_ptr section, + const void *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, 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 (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 (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) + (_("%B: unsupported relocation type %s"), + abfd, areloc->howto->name); + bfd_set_error (bfd_error_bad_value); + return FALSE; +} + +bfd_boolean +_bfd_elf_close_and_cleanup (bfd *abfd) +{ + if (bfd_get_format (abfd) == bfd_object) + { + if (elf_shstrtab (abfd) != NULL) + _bfd_elf_strtab_free (elf_shstrtab (abfd)); + _bfd_dwarf2_cleanup_debug_info (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 + (bfd *abfd ATTRIBUTE_UNUSED, arelent *re ATTRIBUTE_UNUSED, + struct bfd_symbol *symbol ATTRIBUTE_UNUSED, + void *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 (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 (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->size = sect->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 (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, len); + if (threaded_name == NULL) + return FALSE; + memcpy (threaded_name, buf, len); + + sect = bfd_make_section_anyway (abfd, threaded_name); + if (sect == NULL) + return FALSE; + sect->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 (bfd *abfd, Elf_Internal_Note *note) +{ + size_t size; + int offset; + + if (note->descsz == sizeof (prstatus_t)) + { + prstatus_t prstat; + + 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; + + 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", + 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 (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 (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 (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 (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, 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 (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 (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 (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, len); + if (name == NULL) + return FALSE; + memcpy (name, buf, len); + + sect = bfd_make_section_anyway (abfd, name); + if (sect == NULL) + return FALSE; + +#if defined (HAVE_LWPSTATUS_T_PR_CONTEXT) + sect->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->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, len); + if (name == NULL) + return FALSE; + memcpy (name, buf, len); + + sect = bfd_make_section_anyway (abfd, name); + if (sect == NULL) + return FALSE; + +#if defined (HAVE_LWPSTATUS_T_PR_CONTEXT) + sect->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->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 (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/%ld", (long) pstatus.data.thread_info.tid); + + len = strlen (buf) + 1; + name = bfd_alloc (abfd, len); + if (name == NULL) + return FALSE; + + memcpy (name, buf, len); + + sect = bfd_make_section_anyway (abfd, name); + if (sect == NULL) + return FALSE; + + sect->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/%08lx", + (long) pstatus.data.module_info.base_address); + + len = strlen (buf) + 1; + name = bfd_alloc (abfd, len); + if (name == NULL) + return FALSE; + + memcpy (name, buf, len); + + sect = bfd_make_section_anyway (abfd, name); + + if (sect == NULL) + return FALSE; + + sect->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 (bfd *abfd, Elf_Internal_Note *note) +{ + const 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 + + case NT_AUXV: + { + asection *sect = bfd_make_section_anyway (abfd, ".auxv"); + + if (sect == NULL) + return FALSE; + sect->size = note->descsz; + sect->filepos = note->descpos; + sect->flags = SEC_HAS_CONTENTS; + sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32; + + return TRUE; + } + } +} + +static bfd_boolean +elfcore_netbsd_get_lwpid (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 (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 elfcore_make_note_pseudosection (abfd, ".note.netbsdcore.procinfo", + note); +} + +static bfd_boolean +elfcore_grok_netbsd_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 (bfd *abfd, Elf_Internal_Note *note, pid_t *tid) +{ + void *ddata = note->descdata; + char buf[100]; + char *name; + asection *sect; + short sig; + unsigned flags; + + /* 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. Pass it back. */ + *tid = bfd_get_32 (abfd, (bfd_byte *) ddata + 4); + + /* nto_procfs_status 'flags' field is at offset 8. */ + flags = bfd_get_32 (abfd, (bfd_byte *) ddata + 8); + + /* nto_procfs_status 'what' field is at offset 14. */ + if ((sig = bfd_get_16 (abfd, (bfd_byte *) ddata + 14)) > 0) + { + elf_tdata (abfd)->core_signal = sig; + elf_tdata (abfd)->core_lwpid = *tid; + } + + /* _DEBUG_FLAG_CURTID (current thread) is 0x80. Some cores + do not come from signals so we make sure we set the current + thread just in case. */ + if (flags & 0x00000080) + elf_tdata (abfd)->core_lwpid = *tid; + + /* Make a ".qnx_core_status/%d" section. */ + sprintf (buf, ".qnx_core_status/%ld", (long) *tid); + + name = bfd_alloc (abfd, strlen (buf) + 1); + if (name == NULL) + return FALSE; + strcpy (name, buf); + + sect = bfd_make_section_anyway (abfd, name); + if (sect == NULL) + return FALSE; + + sect->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_regs (bfd *abfd, + Elf_Internal_Note *note, + pid_t tid, + char *base) +{ + char buf[100]; + char *name; + asection *sect; + + /* Make a "(base)/%d" section. */ + sprintf (buf, "%s/%ld", base, (long) tid); + + name = bfd_alloc (abfd, strlen (buf) + 1); + if (name == NULL) + return FALSE; + strcpy (name, buf); + + sect = bfd_make_section_anyway (abfd, name); + if (sect == NULL) + return FALSE; + + sect->size = note->descsz; + sect->filepos = note->descpos; + sect->flags = SEC_HAS_CONTENTS; + sect->alignment_power = 2; + + /* This is the current thread. */ + if (elf_tdata (abfd)->core_lwpid == tid) + return elfcore_maybe_make_sect (abfd, base, sect); + + return TRUE; +} + +#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 (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_regs (abfd, note, tid, ".reg"); + case BFD_QNT_CORE_FPREG: + return elfcore_grok_nto_regs (abfd, note, tid, ".reg2"); + 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 (bfd *abfd, + char *buf, + int *bufsiz, + const char *name, + int type, + const void *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) + { + const struct elf_backend_data *bed; + + namesz = strlen (name) + 1; + bed = get_elf_backend_data (abfd); + pad = -namesz & ((1 << bed->s->log_file_align) - 1); + } + + newspace = 12 + 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 (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 (bfd *abfd, + char *buf, + int *bufsiz, + long pid, + int cursig, + const void *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 (bfd *abfd, + char *buf, + int *bufsiz, + long pid, + int cursig, + const void *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 (bfd *abfd, + char *buf, + int *bufsiz, + long pid, + int cursig ATTRIBUTE_UNUSED, + const void *gregs ATTRIBUTE_UNUSED) +{ + 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 (bfd *abfd, + char *buf, + int *bufsiz, + const void *fpregs, + int size) +{ + char *note_name = "CORE"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_FPREGSET, fpregs, size); +} + +char * +elfcore_write_prxfpreg (bfd *abfd, + char *buf, + int *bufsiz, + const void *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 (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 (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 (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 (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 (bfd *abfd ATTRIBUTE_UNUSED, void *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 (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 (bfd *abfd, + Elf_Internal_Sym *sym, + asection **psec, + Elf_Internal_Rela *rel) +{ + asection *sec = *psec; + bfd_vma relocation; + + relocation = (sec->output_section->vma + + sec->output_offset + + sym->st_value); + if ((sec->flags & SEC_MERGE) + && ELF_ST_TYPE (sym->st_info) == STT_SECTION + && sec->sec_info_type == ELF_INFO_TYPE_MERGE) + { + rel->r_addend = + _bfd_merged_section_offset (abfd, psec, + elf_section_data (sec)->sec_info, + sym->st_value + rel->r_addend); + if (sec != *psec) + { + /* If we have changed the section, and our original section is + marked with SEC_EXCLUDE, it means that the original + SEC_MERGE section has been completely subsumed in some + other SEC_MERGE section. In this case, we need to leave + some info around for --emit-relocs. */ + if ((sec->flags & SEC_EXCLUDE) != 0) + sec->kept_section = *psec; + sec = *psec; + } + rel->r_addend -= relocation; + rel->r_addend += sec->output_section->vma + sec->output_offset; + } + return relocation; +} + +bfd_vma +_bfd_elf_rel_local_sym (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 +_bfd_elf_section_offset (bfd *abfd, + struct bfd_link_info *info, + asection *sec, + bfd_vma offset) +{ + switch (sec->sec_info_type) + { + case ELF_INFO_TYPE_STABS: + return _bfd_stab_section_offset (sec, elf_section_data (sec)->sec_info, + offset); + case ELF_INFO_TYPE_EH_FRAME: + return _bfd_elf_eh_frame_section_offset (abfd, info, sec, offset); + default: + return offset; + } +} + +/* Create a new BFD as if by bfd_openr. Rather than opening a file, + reconstruct an ELF file by reading the segments out of remote memory + based on the ELF file header at EHDR_VMA and the ELF program headers it + points to. If not null, *LOADBASEP is filled in with the difference + between the VMAs from which the segments were read, and the VMAs the + file headers (and hence BFD's idea of each section's VMA) put them at. + + The function TARGET_READ_MEMORY is called to copy LEN bytes from the + remote memory at target address VMA into the local buffer at MYADDR; it + should return zero on success or an `errno' code on failure. TEMPL must + be a BFD for an ELF target with the word size and byte order found in + the remote memory. */ + +bfd * +bfd_elf_bfd_from_remote_memory + (bfd *templ, + bfd_vma ehdr_vma, + bfd_vma *loadbasep, + int (*target_read_memory) (bfd_vma, bfd_byte *, int)) +{ + return (*get_elf_backend_data (templ)->elf_backend_bfd_from_remote_memory) + (templ, ehdr_vma, loadbasep, target_read_memory); +} + +long +_bfd_elf_get_synthetic_symtab (bfd *abfd, + long symcount ATTRIBUTE_UNUSED, + asymbol **syms ATTRIBUTE_UNUSED, + long dynsymcount, + asymbol **dynsyms, + asymbol **ret) +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + asection *relplt; + asymbol *s; + const char *relplt_name; + bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); + arelent *p; + long count, i, n; + size_t size; + Elf_Internal_Shdr *hdr; + char *names; + asection *plt; + + *ret = NULL; + + if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0) + return 0; + + if (dynsymcount <= 0) + return 0; + + if (!bed->plt_sym_val) + return 0; + + relplt_name = bed->relplt_name; + if (relplt_name == NULL) + relplt_name = bed->default_use_rela_p ? ".rela.plt" : ".rel.plt"; + relplt = bfd_get_section_by_name (abfd, relplt_name); + if (relplt == NULL) + return 0; + + hdr = &elf_section_data (relplt)->this_hdr; + if (hdr->sh_link != elf_dynsymtab (abfd) + || (hdr->sh_type != SHT_REL && hdr->sh_type != SHT_RELA)) + return 0; + + plt = bfd_get_section_by_name (abfd, ".plt"); + if (plt == NULL) + return 0; + + slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; + if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) + return -1; + + count = relplt->size / hdr->sh_entsize; + size = count * sizeof (asymbol); + p = relplt->relocation; + for (i = 0; i < count; i++, s++, p++) + size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt"); + + s = *ret = bfd_malloc (size); + if (s == NULL) + return -1; + + names = (char *) (s + count); + p = relplt->relocation; + n = 0; + for (i = 0; i < count; i++, s++, p++) + { + size_t len; + bfd_vma addr; + + addr = bed->plt_sym_val (i, plt, p); + if (addr == (bfd_vma) -1) + continue; + + *s = **p->sym_ptr_ptr; + /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since + we are defining a symbol, ensure one of them is set. */ + if ((s->flags & BSF_LOCAL) == 0) + s->flags |= BSF_GLOBAL; + s->section = plt; + s->value = addr - plt->vma; + s->name = names; + len = strlen ((*p->sym_ptr_ptr)->name); + memcpy (names, (*p->sym_ptr_ptr)->name, len); + names += len; + memcpy (names, "@plt", sizeof ("@plt")); + names += sizeof ("@plt"); + ++n; + } + + return n; +} + +/* Sort symbol by binding and section. We want to put definitions + sorted by section at the beginning. */ + +static int +elf_sort_elf_symbol (const void *arg1, const void *arg2) +{ + const Elf_Internal_Sym *s1; + const Elf_Internal_Sym *s2; + int shndx; + + /* Make sure that undefined symbols are at the end. */ + s1 = (const Elf_Internal_Sym *) arg1; + if (s1->st_shndx == SHN_UNDEF) + return 1; + s2 = (const Elf_Internal_Sym *) arg2; + if (s2->st_shndx == SHN_UNDEF) + return -1; + + /* Sorted by section index. */ + shndx = s1->st_shndx - s2->st_shndx; + if (shndx != 0) + return shndx; + + /* Sorted by binding. */ + return ELF_ST_BIND (s1->st_info) - ELF_ST_BIND (s2->st_info); +} + +struct elf_symbol +{ + Elf_Internal_Sym *sym; + const char *name; +}; + +static int +elf_sym_name_compare (const void *arg1, const void *arg2) +{ + const struct elf_symbol *s1 = (const struct elf_symbol *) arg1; + const struct elf_symbol *s2 = (const struct elf_symbol *) arg2; + return strcmp (s1->name, s2->name); +} + +/* Check if 2 sections define the same set of local and global + symbols. */ + +bfd_boolean +bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2) +{ + bfd *bfd1, *bfd2; + const struct elf_backend_data *bed1, *bed2; + Elf_Internal_Shdr *hdr1, *hdr2; + bfd_size_type symcount1, symcount2; + Elf_Internal_Sym *isymbuf1, *isymbuf2; + Elf_Internal_Sym *isymstart1 = NULL, *isymstart2 = NULL, *isym; + Elf_Internal_Sym *isymend; + struct elf_symbol *symp, *symtable1 = NULL, *symtable2 = NULL; + bfd_size_type count1, count2, i; + int shndx1, shndx2; + bfd_boolean result; + + bfd1 = sec1->owner; + bfd2 = sec2->owner; + + /* If both are .gnu.linkonce sections, they have to have the same + section name. */ + if (strncmp (sec1->name, ".gnu.linkonce", + sizeof ".gnu.linkonce" - 1) == 0 + && strncmp (sec2->name, ".gnu.linkonce", + sizeof ".gnu.linkonce" - 1) == 0) + return strcmp (sec1->name + sizeof ".gnu.linkonce", + sec2->name + sizeof ".gnu.linkonce") == 0; + + /* Both sections have to be in ELF. */ + if (bfd_get_flavour (bfd1) != bfd_target_elf_flavour + || bfd_get_flavour (bfd2) != bfd_target_elf_flavour) + return FALSE; + + if (elf_section_type (sec1) != elf_section_type (sec2)) + return FALSE; + + if ((elf_section_flags (sec1) & SHF_GROUP) != 0 + && (elf_section_flags (sec2) & SHF_GROUP) != 0) + { + /* If both are members of section groups, they have to have the + same group name. */ + if (strcmp (elf_group_name (sec1), elf_group_name (sec2)) != 0) + return FALSE; + } + + shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1); + shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2); + if (shndx1 == -1 || shndx2 == -1) + return FALSE; + + bed1 = get_elf_backend_data (bfd1); + bed2 = get_elf_backend_data (bfd2); + hdr1 = &elf_tdata (bfd1)->symtab_hdr; + symcount1 = hdr1->sh_size / bed1->s->sizeof_sym; + hdr2 = &elf_tdata (bfd2)->symtab_hdr; + symcount2 = hdr2->sh_size / bed2->s->sizeof_sym; + + if (symcount1 == 0 || symcount2 == 0) + return FALSE; + + isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0, + NULL, NULL, NULL); + isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0, + NULL, NULL, NULL); + + result = FALSE; + if (isymbuf1 == NULL || isymbuf2 == NULL) + goto done; + + /* Sort symbols by binding and section. Global definitions are at + the beginning. */ + qsort (isymbuf1, symcount1, sizeof (Elf_Internal_Sym), + elf_sort_elf_symbol); + qsort (isymbuf2, symcount2, sizeof (Elf_Internal_Sym), + elf_sort_elf_symbol); + + /* Count definitions in the section. */ + count1 = 0; + for (isym = isymbuf1, isymend = isym + symcount1; + isym < isymend; isym++) + { + if (isym->st_shndx == (unsigned int) shndx1) + { + if (count1 == 0) + isymstart1 = isym; + count1++; + } + + if (count1 && isym->st_shndx != (unsigned int) shndx1) + break; + } + + count2 = 0; + for (isym = isymbuf2, isymend = isym + symcount2; + isym < isymend; isym++) + { + if (isym->st_shndx == (unsigned int) shndx2) + { + if (count2 == 0) + isymstart2 = isym; + count2++; + } + + if (count2 && isym->st_shndx != (unsigned int) shndx2) + break; + } + + if (count1 == 0 || count2 == 0 || count1 != count2) + goto done; + + symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol)); + symtable2 = bfd_malloc (count1 * sizeof (struct elf_symbol)); + + if (symtable1 == NULL || symtable2 == NULL) + goto done; + + symp = symtable1; + for (isym = isymstart1, isymend = isym + count1; + isym < isymend; isym++) + { + symp->sym = isym; + symp->name = bfd_elf_string_from_elf_section (bfd1, + hdr1->sh_link, + isym->st_name); + symp++; + } + + symp = symtable2; + for (isym = isymstart2, isymend = isym + count1; + isym < isymend; isym++) + { + symp->sym = isym; + symp->name = bfd_elf_string_from_elf_section (bfd2, + hdr2->sh_link, + isym->st_name); + symp++; + } + + /* Sort symbol by name. */ + qsort (symtable1, count1, sizeof (struct elf_symbol), + elf_sym_name_compare); + qsort (symtable2, count1, sizeof (struct elf_symbol), + elf_sym_name_compare); + + for (i = 0; i < count1; i++) + /* Two symbols must have the same binding, type and name. */ + if (symtable1 [i].sym->st_info != symtable2 [i].sym->st_info + || symtable1 [i].sym->st_other != symtable2 [i].sym->st_other + || strcmp (symtable1 [i].name, symtable2 [i].name) != 0) + goto done; + + result = TRUE; + +done: + if (symtable1) + free (symtable1); + if (symtable2) + free (symtable2); + if (isymbuf1) + free (isymbuf1); + if (isymbuf2) + free (isymbuf2); + + return result; +} + +/* It is only used by x86-64 so far. */ +asection _bfd_elf_large_com_section + = BFD_FAKE_SECTION (_bfd_elf_large_com_section, + SEC_IS_COMMON, NULL, NULL, "LARGE_COMMON", + 0); + +/* Return TRUE if 2 section types are compatible. */ + +bfd_boolean +_bfd_elf_match_sections_by_type (bfd *abfd, const asection *asec, + bfd *bbfd, const asection *bsec) +{ + if (asec == NULL + || bsec == NULL + || abfd->xvec->flavour != bfd_target_elf_flavour + || bbfd->xvec->flavour != bfd_target_elf_flavour) + return TRUE; + + return elf_section_type (asec) == elf_section_type (bsec); +} diff --git a/contrib/binutils-2.17/bfd/elf32-i386.c b/contrib/binutils-2.17/bfd/elf32-i386.c new file mode 100644 index 0000000000..754aa52254 --- /dev/null +++ b/contrib/binutils-2.17/bfd/elf32-i386.c @@ -0,0 +1,4004 @@ +/* Intel 80386/80486-specific support for 32-bit ELF + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + 2003, 2004, 2005, 2006 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf-vxworks.h" + +/* 386 uses REL relocations instead of RELA. */ +#define USE_REL 1 + +#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 (R_386_GOTPC + 1) +#define R_386_ext_offset (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 (R_386_PC8 + 1 - R_386_ext_offset) +#define R_386_tls_offset (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), + EMPTY_HOWTO (38), + HOWTO(R_386_TLS_GOTDESC, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_GOTDESC", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_DESC_CALL, 0, 0, 0, FALSE, 0, complain_overflow_dont, + bfd_elf_generic_reloc, "R_386_TLS_DESC_CALL", + FALSE, 0, 0, FALSE), + HOWTO(R_386_TLS_DESC, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_DESC", + TRUE, 0xffffffff, 0xffffffff, FALSE), + + /* Another gap. */ +#define R_386_tls (R_386_TLS_DESC + 1 - R_386_tls_offset) +#define R_386_vt_offset (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 (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 (bfd *abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type code) +{ + switch (code) + { + case BFD_RELOC_NONE: + TRACE ("BFD_RELOC_NONE"); + return &elf_howto_table[R_386_NONE]; + + case BFD_RELOC_32: + TRACE ("BFD_RELOC_32"); + return &elf_howto_table[R_386_32]; + + case BFD_RELOC_CTOR: + TRACE ("BFD_RELOC_CTOR"); + return &elf_howto_table[R_386_32]; + + case BFD_RELOC_32_PCREL: + TRACE ("BFD_RELOC_PC32"); + return &elf_howto_table[R_386_PC32]; + + case BFD_RELOC_386_GOT32: + TRACE ("BFD_RELOC_386_GOT32"); + return &elf_howto_table[R_386_GOT32]; + + case BFD_RELOC_386_PLT32: + TRACE ("BFD_RELOC_386_PLT32"); + return &elf_howto_table[R_386_PLT32]; + + case BFD_RELOC_386_COPY: + TRACE ("BFD_RELOC_386_COPY"); + return &elf_howto_table[R_386_COPY]; + + case BFD_RELOC_386_GLOB_DAT: + TRACE ("BFD_RELOC_386_GLOB_DAT"); + return &elf_howto_table[R_386_GLOB_DAT]; + + case BFD_RELOC_386_JUMP_SLOT: + TRACE ("BFD_RELOC_386_JUMP_SLOT"); + return &elf_howto_table[R_386_JUMP_SLOT]; + + case BFD_RELOC_386_RELATIVE: + TRACE ("BFD_RELOC_386_RELATIVE"); + return &elf_howto_table[R_386_RELATIVE]; + + case BFD_RELOC_386_GOTOFF: + TRACE ("BFD_RELOC_386_GOTOFF"); + return &elf_howto_table[R_386_GOTOFF]; + + case BFD_RELOC_386_GOTPC: + TRACE ("BFD_RELOC_386_GOTPC"); + return &elf_howto_table[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[R_386_TLS_TPOFF - R_386_ext_offset]; + + case BFD_RELOC_386_TLS_IE: + TRACE ("BFD_RELOC_386_TLS_IE"); + return &elf_howto_table[R_386_TLS_IE - R_386_ext_offset]; + + case BFD_RELOC_386_TLS_GOTIE: + TRACE ("BFD_RELOC_386_TLS_GOTIE"); + return &elf_howto_table[R_386_TLS_GOTIE - R_386_ext_offset]; + + case BFD_RELOC_386_TLS_LE: + TRACE ("BFD_RELOC_386_TLS_LE"); + return &elf_howto_table[R_386_TLS_LE - R_386_ext_offset]; + + case BFD_RELOC_386_TLS_GD: + TRACE ("BFD_RELOC_386_TLS_GD"); + return &elf_howto_table[R_386_TLS_GD - R_386_ext_offset]; + + case BFD_RELOC_386_TLS_LDM: + TRACE ("BFD_RELOC_386_TLS_LDM"); + return &elf_howto_table[R_386_TLS_LDM - R_386_ext_offset]; + + case BFD_RELOC_16: + TRACE ("BFD_RELOC_16"); + return &elf_howto_table[R_386_16 - R_386_ext_offset]; + + case BFD_RELOC_16_PCREL: + TRACE ("BFD_RELOC_16_PCREL"); + return &elf_howto_table[R_386_PC16 - R_386_ext_offset]; + + case BFD_RELOC_8: + TRACE ("BFD_RELOC_8"); + return &elf_howto_table[R_386_8 - R_386_ext_offset]; + + case BFD_RELOC_8_PCREL: + TRACE ("BFD_RELOC_8_PCREL"); + return &elf_howto_table[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[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[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[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[R_386_TLS_DTPMOD32 - R_386_tls_offset]; + + case BFD_RELOC_386_TLS_DTPOFF32: + TRACE ("BFD_RELOC_386_TLS_DTPOFF32"); + return &elf_howto_table[R_386_TLS_DTPOFF32 - R_386_tls_offset]; + + case BFD_RELOC_386_TLS_TPOFF32: + TRACE ("BFD_RELOC_386_TLS_TPOFF32"); + return &elf_howto_table[R_386_TLS_TPOFF32 - R_386_tls_offset]; + + case BFD_RELOC_386_TLS_GOTDESC: + TRACE ("BFD_RELOC_386_TLS_GOTDESC"); + return &elf_howto_table[R_386_TLS_GOTDESC - R_386_tls_offset]; + + case BFD_RELOC_386_TLS_DESC_CALL: + TRACE ("BFD_RELOC_386_TLS_DESC_CALL"); + return &elf_howto_table[R_386_TLS_DESC_CALL - R_386_tls_offset]; + + case BFD_RELOC_386_TLS_DESC: + TRACE ("BFD_RELOC_386_TLS_DESC"); + return &elf_howto_table[R_386_TLS_DESC - R_386_tls_offset]; + + case BFD_RELOC_VTABLE_INHERIT: + TRACE ("BFD_RELOC_VTABLE_INHERIT"); + return &elf_howto_table[R_386_GNU_VTINHERIT - R_386_vt_offset]; + + case BFD_RELOC_VTABLE_ENTRY: + TRACE ("BFD_RELOC_VTABLE_ENTRY"); + return &elf_howto_table[R_386_GNU_VTENTRY - R_386_vt_offset]; + + default: + break; + } + + TRACE ("Unknown"); + return 0; +} + +static void +elf_i386_info_to_howto_rel (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) (_("%B: invalid relocation type %d"), + abfd, (int) r_type); + indx = 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 (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 (bfd *abfd, Elf_Internal_Note *note) +{ + int offset; + size_t size; + + if (note->namesz == 8 && strcmp (note->namedata, "FreeBSD") == 0) + { + int pr_version = bfd_get_32 (abfd, note->descdata); + + if (pr_version != 1) + return FALSE; + + /* pr_cursig */ + elf_tdata (abfd)->core_signal = bfd_get_32 (abfd, note->descdata + 20); + + /* pr_pid */ + elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); + + /* pr_reg */ + offset = 28; + size = bfd_get_32 (abfd, note->descdata + 8); + } + else + { + 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; + size = 68; + + break; + } + } + + /* Make a ".reg/999" section. */ + return _bfd_elfcore_make_pseudosection (abfd, ".reg", + size, note->descpos + offset); +} + +static bfd_boolean +elf_i386_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) +{ + if (note->namesz == 8 && strcmp (note->namedata, "FreeBSD") == 0) + { + int pr_version = bfd_get_32 (abfd, note->descdata); + + if (pr_version != 1) + return FALSE; + + elf_tdata (abfd)->core_program + = _bfd_elfcore_strndup (abfd, note->descdata + 8, 17); + elf_tdata (abfd)->core_command + = _bfd_elfcore_strndup (abfd, note->descdata + 25, 81); + } + else + { + 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. + Will be padded to PLT_ENTRY_SIZE with htab->plt0_pad_byte. */ + +static const bfd_byte elf_i386_plt0_entry[12] = +{ + 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. */ +}; + +/* 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. + Will be padded to PLT_ENTRY_SIZE with htab->plt0_pad_byte. */ + +static const bfd_byte elf_i386_pic_plt0_entry[12] = +{ + 0xff, 0xb3, 4, 0, 0, 0, /* pushl 4(%ebx) */ + 0xff, 0xa3, 8, 0, 0, 0 /* jmp *8(%ebx) */ +}; + +/* 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. */ +}; + +/* On VxWorks, the .rel.plt.unloaded section has absolute relocations + for the PLTResolve stub and then for each PLT entry. */ +#define PLTRESOLVE_RELOCS_SHLIB 0 +#define PLTRESOLVE_RELOCS 2 +#define PLT_NON_JUMP_SLOT_RELOCS 2 + +/* 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 +#define GOT_TLS_GDESC 8 +#define GOT_TLS_MASK 0x0f +#define GOT_TLS_IE_IE 0x10 +#define GOT_TLS_IE_GD 0x20 +#define GOT_TLS_IE_MASK 0x30 +#define GOT_TLS_GD_BOTH_P(type) \ + ((type) == (GOT_TLS_GD | GOT_TLS_GDESC)) +#define GOT_TLS_GD_P(type) \ + ((type) == GOT_TLS_GD || GOT_TLS_GD_BOTH_P (type)) +#define GOT_TLS_GDESC_P(type) \ + ((type) == GOT_TLS_GDESC || GOT_TLS_GD_BOTH_P (type)) +#define GOT_TLS_GD_ANY_P(type) \ + (GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type)) + unsigned char tls_type; + + /* Offset of the GOTPLT entry reserved for the TLS descriptor, + starting at the end of the jump table. */ + bfd_vma tlsdesc_got; +}; + +#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; + + /* GOTPLT entries for TLS descriptors. */ + bfd_vma *local_tlsdesc_gotent; +}; + +#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) + +#define elf_i386_local_tlsdesc_gotent(abfd) \ + (elf_i386_tdata (abfd)->local_tlsdesc_gotent) + +static bfd_boolean +elf_i386_mkobject (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; +} + +/* 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; + + /* The (unloaded but important) .rel.plt.unloaded section on VxWorks. */ + asection *srelplt2; + + /* True if the target system is VxWorks. */ + int is_vxworks; + + /* Value used to fill the last word of the first plt entry. */ + bfd_byte plt0_pad_byte; + + /* The index of the next unused R_386_TLS_DESC slot in .rel.plt. */ + bfd_vma next_tls_desc_index; + + union { + bfd_signed_vma refcount; + bfd_vma offset; + } tls_ldm_got; + + /* The amount of space used by the reserved portion of the sgotplt + section, plus whatever space is used by the jump slots. */ + bfd_vma sgotplt_jump_table_size; + + /* 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)) + +#define elf_i386_compute_jump_table_size(htab) \ + ((htab)->next_tls_desc_index * 4) + +/* Create an entry in an i386 ELF linker hash table. */ + +static struct bfd_hash_entry * +link_hash_newfunc (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; + eh->tlsdesc_got = (bfd_vma) -1; + } + + return entry; +} + +/* Create an i386 ELF linker hash table. */ + +static struct bfd_link_hash_table * +elf_i386_link_hash_table_create (bfd *abfd) +{ + struct elf_i386_link_hash_table *ret; + bfd_size_type amt = sizeof (struct elf_i386_link_hash_table); + + ret = bfd_malloc (amt); + if (ret == NULL) + return NULL; + + if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc, + sizeof (struct elf_i386_link_hash_entry))) + { + 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->next_tls_desc_index = 0; + ret->sgotplt_jump_table_size = 0; + ret->sym_sec.abfd = NULL; + ret->is_vxworks = 0; + ret->srelplt2 = NULL; + ret->plt0_pad_byte = 0; + + 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 (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_with_flags (dynobj, ".rel.got", + (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_LINKER_CREATED + | SEC_READONLY)); + if (htab->srelgot == NULL + || ! 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 (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 (); + + if (htab->is_vxworks + && !elf_vxworks_create_dynamic_sections (dynobj, info, &htab->srelplt2)) + return FALSE; + + return TRUE; +} + +/* Copy the extra info we tack onto an elf_link_hash_entry. */ + +static void +elf_i386_copy_indirect_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *dir, + struct elf_link_hash_entry *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; + + /* Add reloc counts against the indirect sym to the direct sym + list. Merge any entries against the same section. */ + for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) + { + struct elf_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->dynamic_adjusted) + { + /* If called to transfer flags for a weakdef during processing + of elf_adjust_dynamic_symbol, don't copy non_got_ref. + We clear it ourselves for ELIMINATE_COPY_RELOCS. */ + dir->ref_dynamic |= ind->ref_dynamic; + dir->ref_regular |= ind->ref_regular; + dir->ref_regular_nonweak |= ind->ref_regular_nonweak; + dir->needs_plt |= ind->needs_plt; + dir->pointer_equality_needed |= ind->pointer_equality_needed; + } + else + _bfd_elf_link_hash_copy_indirect (info, dir, ind); +} + +static int +elf_i386_tls_transition (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_GOTDESC: + case R_386_TLS_DESC_CALL: + 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 (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->relocatable) + 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) (_("%B: bad symbol index: %d"), + abfd, + r_symndx); + return FALSE; + } + + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + } + + 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->needs_plt = 1; + 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: + case R_386_TLS_GOTDESC: + case R_386_TLS_DESC_CALL: + /* 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_GOTDESC: + case R_386_TLS_DESC_CALL: + tls_type = GOT_TLS_GDESC; break; + case R_386_TLS_IE_32: + if (ELF32_R_TYPE (rel->r_info) == r_type) + tls_type = GOT_TLS_IE_NEG; + else if (h + && ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD) + /* If this is a GD->IE transition, we may use either + of R_386_TLS_TPOFF and R_386_TLS_TPOFF32. But if + we may have both R_386_TLS_IE and R_386_TLS_GD, + we can't share the same R_386_TLS_TPOFF since + they require different offsets. So we remember + it comes from R_386_TLS_GD. */ + tls_type = GOT_TLS_IE | GOT_TLS_IE_GD; + else + tls_type = GOT_TLS_IE; + break; + case R_386_TLS_IE: + if (h) + { + /* We remember it comes from R_386_TLS_IE. */ + tls_type = GOT_TLS_IE_POS | GOT_TLS_IE_IE; + break; + } + 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 (bfd_vma) + sizeof(char)); + local_got_refcounts = bfd_zalloc (abfd, size); + if (local_got_refcounts == NULL) + return FALSE; + elf_local_got_refcounts (abfd) = local_got_refcounts; + elf_i386_local_tlsdesc_gotent (abfd) + = (bfd_vma *) (local_got_refcounts + symtab_hdr->sh_info); + elf_i386_local_got_tls_type (abfd) + = (char *) (local_got_refcounts + 2 * 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 + && (! GOT_TLS_GD_ANY_P (old_tls_type) + || (tls_type & GOT_TLS_IE) == 0)) + { + if ((old_tls_type & GOT_TLS_IE) && GOT_TLS_GD_ANY_P (tls_type)) + tls_type = old_tls_type; + else if (GOT_TLS_GD_ANY_P (old_tls_type) + && GOT_TLS_GD_ANY_P (tls_type)) + tls_type |= old_tls_type; + else + { + (*_bfd_error_handler) + (_("%B: `%s' accessed both as normal and " + "thread local symbol"), + 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->non_got_ref = 1; + + /* We may need a .plt entry if the function this reloc + refers to is in a shared lib. */ + h->plt.refcount += 1; + if (r_type != R_386_PC32) + h->pointer_equality_needed = 1; + } + + /* If we are creating a shared library, and this is a reloc + against a global symbol, or a non PC relative reloc + against a local symbol, then we need to copy the reloc + into the shared library. However, if we are linking with + -Bsymbolic, we do not need to copy a reloc against a + global symbol which is defined in an object we are + including in the link (i.e., DEF_REGULAR is set). At + this point we have not seen all the input files, so it is + possible that DEF_REGULAR is not set now but will be set + later (it is never cleared). In case of a weak definition, + DEF_REGULAR may be cleared later by a strong definition in + a shared library. We account for that possibility below by + storing information in the relocs_copied field of the hash + table entry. A similar situation occurs when creating + shared libraries and symbol visibility changes render the + symbol local. + + If on the other hand, we are creating an executable, we + may need to keep relocations for symbols satisfied by a + dynamic library if we manage to avoid copy relocs for the + symbol. */ + if ((info->shared + && (sec->flags & SEC_ALLOC) != 0 + && (r_type != R_386_PC32 + || (h != NULL + && (! info->symbolic + || h->root.type == bfd_link_hash_defweak + || !h->def_regular)))) + || (ELIMINATE_COPY_RELOCS + && !info->shared + && (sec->flags & SEC_ALLOC) != 0 + && h != NULL + && (h->root.type == bfd_link_hash_defweak + || !h->def_regular))) + { + 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) + (_("%B: bad relocation section name `%s\'"), + 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; + + flags = (SEC_HAS_CONTENTS | SEC_READONLY + | SEC_IN_MEMORY | SEC_LINKER_CREATED); + if ((sec->flags & SEC_ALLOC) != 0) + flags |= SEC_ALLOC | SEC_LOAD; + sreloc = bfd_make_section_with_flags (dynobj, + name, + flags); + if (sreloc == NULL + || ! 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 + { + void **vpp; + /* 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; + + vpp = &elf_section_data (s)->local_dynrel; + head = (struct elf_i386_dyn_relocs **)vpp; + } + + p = *head; + if (p == NULL || p->sec != sec) + { + bfd_size_type amt = sizeof *p; + p = 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_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) + return FALSE; + break; + + /* This relocation describes which C++ vtable entries are actually + used. Record for later use during GC. */ + case R_386_GNU_VTENTRY: + if (!bfd_elf_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 (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 (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]; + 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; + 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_GOTDESC: + case R_386_TLS_DESC_CALL: + 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 (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->needs_plt) + { + if (h->plt.refcount <= 0 + || SYMBOL_CALLS_LOCAL (info, h) + || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT + && h->root.type == bfd_link_hash_undefweak)) + { + /* 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->needs_plt = 0; + } + + 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->u.weakdef != NULL) + { + BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined + || h->u.weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->u.weakdef->root.u.def.section; + h->root.u.def.value = h->u.weakdef->root.u.def.value; + if (ELIMINATE_COPY_RELOCS || info->nocopyreloc) + h->non_got_ref = h->u.weakdef->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->non_got_ref) + return TRUE; + + /* If -z nocopyreloc was given, we won't generate them either. */ + if (info->nocopyreloc) + { + h->non_got_ref = 0; + return TRUE; + } + + htab = elf_i386_hash_table (info); + + /* If there aren't any dynamic relocs in read-only sections, then + we can keep the dynamic relocs and avoid the copy reloc. This + doesn't work on VxWorks, where we can not have dynamic relocations + (other than copy and jump slot relocations) in an executable. */ + if (ELIMINATE_COPY_RELOCS && !htab->is_vxworks) + { + 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 (p == NULL) + { + h->non_got_ref = 0; + return TRUE; + } + } + + if (h->size == 0) + { + (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"), + h->root.root.string); + 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. */ + + /* 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->size += sizeof (Elf32_External_Rel); + h->needs_copy = 1; + } + + /* We need to figure out the alignment required for this symbol. I + have no idea how ELF linkers handle this. */ + power_of_two = bfd_log2 (h->size); + if (power_of_two > 3) + power_of_two = 3; + + /* Apply the required alignment. */ + s = htab->sdynbss; + s->size = BFD_ALIGN (s->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->size; + + /* Increment the section size to make room for the symbol. */ + s->size += h->size; + + return TRUE; +} + +/* Allocate space in .plt, .got and associated reloc sections for + dynamic relocs. */ + +static bfd_boolean +allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) +{ + struct bfd_link_info *info; + struct elf_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->forced_local) + { + if (! bfd_elf_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->size == 0) + s->size += PLT_ENTRY_SIZE; + + h->plt.offset = s->size; + + /* If this symbol is not defined in a regular file, and we are + not generating a shared library, then set the symbol to this + location in the .plt. This is required to make function + pointers compare as equal between the normal executable and + the shared library. */ + if (! info->shared + && !h->def_regular) + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } + + /* Make room for this entry. */ + s->size += PLT_ENTRY_SIZE; + + /* We also need to make an entry in the .got.plt section, which + will be placed in the .got section by the linker script. */ + htab->sgotplt->size += 4; + + /* We also need to make an entry in the .rel.plt section. */ + htab->srelplt->size += sizeof (Elf32_External_Rel); + htab->next_tls_desc_index++; + + if (htab->is_vxworks && !info->shared) + { + /* VxWorks has a second set of relocations for each PLT entry + in executables. They go in a separate relocation section, + which is processed by the kernel loader. */ + + /* There are two relocations for the initial PLT entry: an + R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 4 and an + R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 8. */ + + if (h->plt.offset == PLT_ENTRY_SIZE) + htab->srelplt2->size += (sizeof (Elf32_External_Rel) * 2); + + /* There are two extra relocations for each subsequent PLT entry: + an R_386_32 relocation for the GOT entry, and an R_386_32 + relocation for the PLT entry. */ + + htab->srelplt2->size += (sizeof (Elf32_External_Rel) * 2); + } + } + else + { + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + } + else + { + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + + eh = (struct elf_i386_link_hash_entry *) h; + eh->tlsdesc_got = (bfd_vma) -1; + + /* 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; + + /* If we have both R_386_TLS_IE and R_386_TLS_GD, GOT_TLS_IE_BOTH + should be used. */ + if ((tls_type & GOT_TLS_IE_MASK) + == (GOT_TLS_IE_IE | GOT_TLS_IE_GD)) + tls_type = GOT_TLS_IE_BOTH; + else + tls_type &= GOT_TLS_MASK; + + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && !h->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + s = htab->sgot; + if (GOT_TLS_GDESC_P (tls_type)) + { + eh->tlsdesc_got = htab->sgotplt->size + - elf_i386_compute_jump_table_size (htab); + htab->sgotplt->size += 8; + h->got.offset = (bfd_vma) -2; + } + if (! GOT_TLS_GDESC_P (tls_type) + || GOT_TLS_GD_P (tls_type)) + { + h->got.offset = s->size; + s->size += 4; + /* R_386_TLS_GD needs 2 consecutive GOT slots. */ + if (GOT_TLS_GD_P (tls_type) || tls_type == GOT_TLS_IE_BOTH) + s->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->size += 2 * sizeof (Elf32_External_Rel); + else if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1) + || (tls_type & GOT_TLS_IE)) + htab->srelgot->size += sizeof (Elf32_External_Rel); + else if (GOT_TLS_GD_P (tls_type)) + htab->srelgot->size += 2 * sizeof (Elf32_External_Rel); + else if (! GOT_TLS_GDESC_P (tls_type) + && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak) + && (info->shared + || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))) + htab->srelgot->size += sizeof (Elf32_External_Rel); + if (GOT_TLS_GDESC_P (tls_type)) + htab->srelplt->size += sizeof (Elf32_External_Rel); + } + else + h->got.offset = (bfd_vma) -1; + + if (eh->dyn_relocs == NULL) + return TRUE; + + /* In the shared -Bsymbolic case, discard space allocated for + dynamic pc-relative relocs against symbols which turn out to be + defined in regular objects. For the normal shared case, discard + space for pc-relative relocs that have become local due to symbol + visibility changes. */ + + if (info->shared) + { + /* The only reloc that uses pc_count is R_386_PC32, which will + appear on a call or on something like ".long foo - .". We + want calls to protected symbols to resolve directly to the + function rather than going via the plt. If people want + function pointer comparisons to work as expected then they + should avoid writing assembly like ".long foo - .". */ + if (SYMBOL_CALLS_LOCAL (info, h)) + { + 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; + } + } + + /* Also discard relocs on undefined weak syms with non-default + visibility. */ + if (eh->dyn_relocs != NULL + && h->root.type == bfd_link_hash_undefweak) + { + if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) + eh->dyn_relocs = NULL; + + /* Make sure undefined weak symbols are output as a dynamic + symbol in PIEs. */ + else if (h->dynindx == -1 + && !h->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + } + } + else 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->non_got_ref + && ((h->def_dynamic + && !h->def_regular) + || (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->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + /* If that succeeded, we know we'll be keeping all the + relocs. */ + if (h->dynindx != -1) + goto keep; + } + + eh->dyn_relocs = NULL; + + keep: ; + } + + /* Finally, allocate space. */ + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + asection *sreloc = elf_section_data (p->sec)->sreloc; + sreloc->size += p->count * sizeof (Elf32_External_Rel); + } + + return TRUE; +} + +/* Find any dynamic relocs that apply to read-only sections. */ + +static bfd_boolean +readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) +{ + struct elf_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 (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->executable) + { + s = bfd_get_section_by_name (dynobj, ".interp"); + if (s == NULL) + abort (); + s->size = sizeof ELF_DYNAMIC_INTERPRETER; + s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; + } + } + + /* Set up .got offsets for local syms, and space for local dynamic + relocs. */ + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + { + bfd_signed_vma *local_got; + bfd_signed_vma *end_local_got; + char *local_tls_type; + bfd_vma *local_tlsdesc_gotent; + 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->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); + local_tlsdesc_gotent = elf_i386_local_tlsdesc_gotent (ibfd); + s = htab->sgot; + srel = htab->srelgot; + for (; local_got < end_local_got; + ++local_got, ++local_tls_type, ++local_tlsdesc_gotent) + { + *local_tlsdesc_gotent = (bfd_vma) -1; + if (*local_got > 0) + { + if (GOT_TLS_GDESC_P (*local_tls_type)) + { + *local_tlsdesc_gotent = htab->sgotplt->size + - elf_i386_compute_jump_table_size (htab); + htab->sgotplt->size += 8; + *local_got = (bfd_vma) -2; + } + if (! GOT_TLS_GDESC_P (*local_tls_type) + || GOT_TLS_GD_P (*local_tls_type)) + { + *local_got = s->size; + s->size += 4; + if (GOT_TLS_GD_P (*local_tls_type) + || *local_tls_type == GOT_TLS_IE_BOTH) + s->size += 4; + } + if (info->shared + || GOT_TLS_GD_ANY_P (*local_tls_type) + || (*local_tls_type & GOT_TLS_IE)) + { + if (*local_tls_type == GOT_TLS_IE_BOTH) + srel->size += 2 * sizeof (Elf32_External_Rel); + else if (GOT_TLS_GD_P (*local_tls_type) + || ! GOT_TLS_GDESC_P (*local_tls_type)) + srel->size += sizeof (Elf32_External_Rel); + if (GOT_TLS_GDESC_P (*local_tls_type)) + htab->srelplt->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->size; + htab->sgot->size += 8; + htab->srelgot->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); + + /* For every jump slot reserved in the sgotplt, reloc_count is + incremented. However, when we reserve space for TLS descriptors, + it's not incremented, so in order to compute the space reserved + for them, it suffices to multiply the reloc count by the jump + slot size. */ + if (htab->srelplt) + htab->sgotplt_jump_table_size = htab->next_tls_desc_index * 4; + + /* 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) + { + bfd_boolean strip_section = TRUE; + + if ((s->flags & SEC_LINKER_CREATED) == 0) + continue; + + if (s == htab->splt + || s == htab->sgot + || s == htab->sgotplt + || s == htab->sdynbss) + { + /* Strip this section if we don't need it; see the + comment below. */ + /* We'd like to strip these sections if they aren't needed, but if + we've exported dynamic symbols from them we must leave them. + It's too late to tell BFD to get rid of the symbols. */ + + if (htab->elf.hplt != NULL) + strip_section = FALSE; + } + else if (strncmp (bfd_get_section_name (dynobj, s), ".rel", 4) == 0) + { + if (s->size != 0 && s != htab->srelplt && s != htab->srelplt2) + relocs = TRUE; + + /* We use the reloc_count field as a counter if we need + to copy relocs into the output file. */ + s->reloc_count = 0; + } + else + { + /* It's not one of our sections, so don't allocate space. */ + continue; + } + + if (s->size == 0) + { + /* If we don't need this section, strip it from the + output file. This is mostly to handle .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. */ + if (strip_section) + s->flags |= SEC_EXCLUDE; + continue; + } + + if ((s->flags & SEC_HAS_CONTENTS) == 0) + continue; + + /* Allocate memory for the section contents. We use bfd_zalloc + here in case unused entries are not reclaimed before the + section's contents are written out. This should not happen, + but this way if it does, we get a R_386_NONE reloc instead + of garbage. */ + s->contents = bfd_zalloc (dynobj, s->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_elf_add_dynamic_entry (info, TAG, VAL) + + if (info->executable) + { + if (!add_dynamic_entry (DT_DEBUG, 0)) + return FALSE; + } + + if (htab->splt->size != 0) + { + if (!add_dynamic_entry (DT_PLTGOT, 0) + || !add_dynamic_entry (DT_PLTRELSZ, 0) + || !add_dynamic_entry (DT_PLTREL, DT_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; +} + +static bfd_boolean +elf_i386_always_size_sections (bfd *output_bfd, + struct bfd_link_info *info) +{ + asection *tls_sec = elf_hash_table (info)->tls_sec; + + if (tls_sec) + { + struct elf_link_hash_entry *tlsbase; + + tlsbase = elf_link_hash_lookup (elf_hash_table (info), + "_TLS_MODULE_BASE_", + FALSE, FALSE, FALSE); + + if (tlsbase && tlsbase->type == STT_TLS) + { + struct bfd_link_hash_entry *bh = NULL; + const struct elf_backend_data *bed + = get_elf_backend_data (output_bfd); + + if (!(_bfd_generic_link_add_one_symbol + (info, output_bfd, "_TLS_MODULE_BASE_", BSF_LOCAL, + tls_sec, 0, NULL, FALSE, + bed->collect, &bh))) + return FALSE; + tlsbase = (struct elf_link_hash_entry *)bh; + tlsbase->def_regular = 1; + tlsbase->other = STV_HIDDEN; + (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE); + } + } + + 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 (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 (struct bfd_link_info *info) +{ + /* If tls_sec is NULL, we should have signalled an error already. */ + if (elf_hash_table (info)->tls_sec == NULL) + return 0; + return elf_hash_table (info)->tls_sec->vma; +} + +/* Return the relocation value for @tpoff relocation + if STT_TLS virtual address is ADDRESS. */ + +static bfd_vma +tpoff (struct bfd_link_info *info, bfd_vma address) +{ + struct elf_link_hash_table *htab = elf_hash_table (info); + + /* If tls_sec is NULL, we should have signalled an error already. */ + if (htab->tls_sec == NULL) + return 0; + return htab->tls_size + htab->tls_sec->vma - address; +} + +/* Relocate an i386 ELF section. */ + +static bfd_boolean +elf_i386_relocate_section (bfd *output_bfd, + struct bfd_link_info *info, + bfd *input_bfd, + asection *input_section, + bfd_byte *contents, + Elf_Internal_Rela *relocs, + Elf_Internal_Sym *local_syms, + asection **local_sections) +{ + struct elf_i386_link_hash_table *htab; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + bfd_vma *local_got_offsets; + bfd_vma *local_tlsdesc_gotents; + 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); + local_tlsdesc_gotents = elf_i386_local_tlsdesc_gotent (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, offplt; + 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 == R_386_GNU_VTINHERIT + || r_type == R_386_GNU_VTENTRY) + continue; + + 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)) + { + (*_bfd_error_handler) + (_("%B: unrecognized relocation (0x%x) in section `%A'"), + input_bfd, input_section, r_type); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + howto = elf_howto_table + indx; + + r_symndx = ELF32_R_SYM (rel->r_info); + + if (info->relocatable) + { + 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 + { + bfd_boolean warned; + + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, + r_symndx, symtab_hdr, sym_hashes, + h, sec, relocation, + unresolved_reloc, warned); + } + + if (r_symndx == 0) + { + /* r_symndx will be zero only for relocs against symbols from + removed linkonce sections, or sections discarded by a linker + script. For these relocs, we just want the section contents + zeroed. Avoid any special processing in the switch below. */ + r_type = R_386_NONE; + + relocation = 0; + if (howto->pc_relative) + relocation = (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset); + } + + 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 + && SYMBOL_REFERENCES_LOCAL (info, h)) + || (ELF_ST_VISIBILITY (h->other) + && h->root.type == bfd_link_hash_undefweak)) + { + /* 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_section->vma + + htab->sgot->output_offset + off + - htab->sgotplt->output_section->vma + - htab->sgotplt->output_offset; + break; + + case R_386_GOTOFF: + /* Relocation is relative to the start of the global offset + table. */ + + /* Check to make sure it isn't a protected function symbol + for shared library since it may not be local when used + as function address. */ + if (info->shared + && !info->executable + && h + && h->def_regular + && h->type == STT_FUNC + && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) + { + (*_bfd_error_handler) + (_("%B: relocation R_386_GOTOFF against protected function `%s' can not be used when making a shared object"), + input_bfd, h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + /* Note that sgot is not involved in this + calculation. We always want the start of .got.plt. 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->sgotplt->output_section->vma + + htab->sgotplt->output_offset; + break; + + case R_386_GOTPC: + /* Use global offset table as symbol value. */ + relocation = htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset; + 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: + if ((input_section->flags & SEC_ALLOC) == 0) + break; + + if ((info->shared + && (h == NULL + || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak) + && (r_type != R_386_PC32 + || !SYMBOL_CALLS_LOCAL (info, h))) + || (ELIMINATE_COPY_RELOCS + && !info->shared + && h != NULL + && h->dynindx != -1 + && !h->non_got_ref + && ((h->def_dynamic + && !h->def_regular) + || h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined))) + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + bfd_boolean skip, 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->def_regular)) + 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_GOTDESC: + case R_386_TLS_DESC_CALL: + 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 we have both R_386_TLS_IE and R_386_TLS_GD, + GOT_TLS_IE_BOTH should be used. */ + if ((tls_type & GOT_TLS_IE_MASK) + == (GOT_TLS_IE_IE | GOT_TLS_IE_GD)) + tls_type = GOT_TLS_IE_BOTH; + else + tls_type &= GOT_TLS_MASK; + 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 + || r_type == R_386_TLS_GOTDESC + || r_type == R_386_TLS_DESC_CALL) + { + 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->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->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_GOTDESC) + { + /* GDesc -> LE transition. + It's originally something like: + leal x@tlsdesc(%ebx), %eax + + leal x@ntpoff, %eax + + Registers other than %eax may be set up here. */ + + unsigned int val, type; + bfd_vma roff; + + /* First, make sure it's a leal adding ebx to a + 32-bit offset into any register, although it's + probably almost always going to be eax. */ + roff = rel->r_offset; + BFD_ASSERT (roff >= 2); + type = bfd_get_8 (input_bfd, contents + roff - 2); + BFD_ASSERT (type == 0x8d); + val = bfd_get_8 (input_bfd, contents + roff - 1); + BFD_ASSERT ((val & 0xc7) == 0x83); + BFD_ASSERT (roff + 4 <= input_section->size); + + /* Now modify the instruction as appropriate. */ + /* aoliva FIXME: remove the above and xor the byte + below with 0x86. */ + bfd_put_8 (output_bfd, val ^ 0x86, + contents + roff - 1); + bfd_put_32 (output_bfd, -tpoff (info, relocation), + contents + roff); + continue; + } + else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_DESC_CALL) + { + /* GDesc -> LE transition. + It's originally: + call *(%eax) + Turn it into: + nop; nop */ + + unsigned int val, type; + bfd_vma roff; + + /* First, make sure it's a call *(%eax). */ + roff = rel->r_offset; + BFD_ASSERT (roff + 2 <= input_section->size); + type = bfd_get_8 (input_bfd, contents + roff); + BFD_ASSERT (type == 0xff); + val = bfd_get_8 (input_bfd, contents + roff + 1); + BFD_ASSERT (val == 0x10); + + /* Now modify the instruction as appropriate. */ + bfd_put_8 (output_bfd, 0x90, contents + roff); + bfd_put_8 (output_bfd, 0x90, contents + roff + 1); + 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->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->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; + offplt = elf_i386_hash_entry (h)->tlsdesc_got; + } + else + { + if (local_got_offsets == NULL) + abort (); + + off = local_got_offsets[r_symndx]; + offplt = local_tlsdesc_gotents[r_symndx]; + } + + if ((off & 1) != 0) + off &= ~1; + else + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + int dr_type, indx; + asection *sreloc; + + if (htab->srelgot == NULL) + abort (); + + indx = h && h->dynindx != -1 ? h->dynindx : 0; + + if (GOT_TLS_GDESC_P (tls_type)) + { + outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_DESC); + BFD_ASSERT (htab->sgotplt_jump_table_size + offplt + 8 + <= htab->sgotplt->size); + outrel.r_offset = (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + offplt + + htab->sgotplt_jump_table_size); + sreloc = htab->srelplt; + loc = sreloc->contents; + loc += (htab->next_tls_desc_index++ + * sizeof (Elf32_External_Rel)); + BFD_ASSERT (loc + sizeof (Elf32_External_Rel) + <= sreloc->contents + sreloc->size); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + if (indx == 0) + { + BFD_ASSERT (! unresolved_reloc); + bfd_put_32 (output_bfd, + relocation - dtpoff_base (info), + htab->sgotplt->contents + offplt + + htab->sgotplt_jump_table_size + 4); + } + else + { + bfd_put_32 (output_bfd, 0, + htab->sgotplt->contents + offplt + + htab->sgotplt_jump_table_size + 4); + } + } + + sreloc = htab->srelgot; + + outrel.r_offset = (htab->sgot->output_section->vma + + htab->sgot->output_offset + off); + + if (GOT_TLS_GD_P (tls_type)) + dr_type = R_386_TLS_DTPMOD32; + else if (GOT_TLS_GDESC_P (tls_type)) + goto dr_done; + 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 if (dr_type != R_386_TLS_DESC) + bfd_put_32 (output_bfd, 0, + htab->sgot->contents + off); + outrel.r_info = ELF32_R_INFO (indx, dr_type); + + loc = sreloc->contents; + loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel); + BFD_ASSERT (loc + sizeof (Elf32_External_Rel) + <= sreloc->contents + sreloc->size); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + + if (GOT_TLS_GD_P (tls_type)) + { + 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; + sreloc->reloc_count++; + loc += sizeof (Elf32_External_Rel); + BFD_ASSERT (loc + sizeof (Elf32_External_Rel) + <= sreloc->contents + sreloc->size); + 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; + sreloc->reloc_count++; + loc += sizeof (Elf32_External_Rel); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + } + + dr_done: + if (h != NULL) + h->got.offset |= 1; + else + local_got_offsets[r_symndx] |= 1; + } + + if (off >= (bfd_vma) -2 + && ! GOT_TLS_GDESC_P (tls_type)) + abort (); + if (r_type == R_386_TLS_GOTDESC + || r_type == R_386_TLS_DESC_CALL) + { + relocation = htab->sgotplt_jump_table_size + offplt; + unresolved_reloc = FALSE; + } + else if (r_type == ELF32_R_TYPE (rel->r_info)) + { + bfd_vma g_o_t = htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset; + relocation = htab->sgot->output_section->vma + + htab->sgot->output_offset + off - g_o_t; + 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 += g_o_t; + unresolved_reloc = FALSE; + } + else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD) + { + 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->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->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_section->vma + + htab->sgot->output_offset + off + - htab->sgotplt->output_section->vma + - htab->sgotplt->output_offset, + contents + roff + 8); + /* Skip R_386_PLT32. */ + rel++; + continue; + } + else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTDESC) + { + /* GDesc -> IE transition. + It's originally something like: + leal x@tlsdesc(%ebx), %eax + + Change it to: + movl x@gotntpoff(%ebx), %eax # before nop; nop + or: + movl x@gottpoff(%ebx), %eax # before negl %eax + + Registers other than %eax may be set up here. */ + + unsigned int val, type; + bfd_vma roff; + + /* First, make sure it's a leal adding ebx to a 32-bit + offset into any register, although it's probably + almost always going to be eax. */ + roff = rel->r_offset; + BFD_ASSERT (roff >= 2); + type = bfd_get_8 (input_bfd, contents + roff - 2); + BFD_ASSERT (type == 0x8d); + val = bfd_get_8 (input_bfd, contents + roff - 1); + BFD_ASSERT ((val & 0xc7) == 0x83); + BFD_ASSERT (roff + 4 <= input_section->size); + + /* Now modify the instruction as appropriate. */ + /* To turn a leal into a movl in the form we use it, it + suffices to change the first byte from 0x8d to 0x8b. + aoliva FIXME: should we decide to keep the leal, all + we have to do is remove the statement below, and + adjust the relaxation of R_386_TLS_DESC_CALL. */ + bfd_put_8 (output_bfd, 0x8b, contents + roff - 2); + + if (tls_type == GOT_TLS_IE_BOTH) + off += 4; + + bfd_put_32 (output_bfd, + htab->sgot->output_section->vma + + htab->sgot->output_offset + off + - htab->sgotplt->output_section->vma + - htab->sgotplt->output_offset, + contents + roff); + continue; + } + else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_DESC_CALL) + { + /* GDesc -> IE transition. + It's originally: + call *(%eax) + + Change it to: + nop; nop + or + negl %eax + depending on how we transformed the TLS_GOTDESC above. + */ + + unsigned int val, type; + bfd_vma roff; + + /* First, make sure it's a call *(%eax). */ + roff = rel->r_offset; + BFD_ASSERT (roff + 2 <= input_section->size); + type = bfd_get_8 (input_bfd, contents + roff); + BFD_ASSERT (type == 0xff); + val = bfd_get_8 (input_bfd, contents + roff + 1); + BFD_ASSERT (val == 0x10); + + /* Now modify the instruction as appropriate. */ + if (tls_type != GOT_TLS_IE_NEG) + { + /* nop; nop */ + bfd_put_8 (output_bfd, 0x90, contents + roff); + bfd_put_8 (output_bfd, 0x90, contents + roff + 1); + } + else + { + /* negl %eax */ + bfd_put_8 (output_bfd, 0xf7, contents + roff); + bfd_put_8 (output_bfd, 0xd8, contents + roff + 1); + } + + continue; + } + else + BFD_ASSERT (FALSE); + 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->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_section->vma + + htab->sgot->output_offset + off + - htab->sgotplt->output_section->vma + - htab->sgotplt->output_offset; + 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->def_dynamic)) + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"), + input_bfd, + input_section, + (long) rel->r_offset, + howto->name, + h->root.root.string); + return FALSE; + } + + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, 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, (h ? &h->root : NULL), name, howto->name, + (bfd_vma) 0, input_bfd, input_section, + rel->r_offset))) + return FALSE; + } + else + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx): reloc against `%s': error %d"), + 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 (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); + + if (htab->is_vxworks) + { + int s, k, reloc_index; + + /* Create the R_386_32 relocation referencing the GOT + for this PLT entry. */ + + /* S: Current slot number (zero-based). */ + s = (h->plt.offset - PLT_ENTRY_SIZE) / PLT_ENTRY_SIZE; + /* K: Number of relocations for PLTResolve. */ + if (info->shared) + k = PLTRESOLVE_RELOCS_SHLIB; + else + k = PLTRESOLVE_RELOCS; + /* Skip the PLTresolve relocations, and the relocations for + the other PLT slots. */ + reloc_index = k + s * PLT_NON_JUMP_SLOT_RELOCS; + loc = (htab->srelplt2->contents + reloc_index + * sizeof (Elf32_External_Rel)); + + rel.r_offset = (htab->splt->output_section->vma + + htab->splt->output_offset + + h->plt.offset + 2), + rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); + + /* Create the R_386_32 relocation referencing the beginning of + the PLT for this GOT entry. */ + rel.r_offset = (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + got_offset); + rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_386_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, + loc + sizeof (Elf32_External_Rel)); + } + } + 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->def_regular) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value if there were any + relocations where pointer equality matters (this is a clue + for the dynamic linker, to make function pointer + comparisons work between an application and shared + library), otherwise set it to zero. If a function is only + called from a binary, there is no need to slow down + shared libraries because of that. */ + sym->st_shndx = SHN_UNDEF; + if (!h->pointer_equality_needed) + sym->st_value = 0; + } + } + + if (h->got.offset != (bfd_vma) -1 + && ! GOT_TLS_GD_ANY_P (elf_i386_hash_entry(h)->tls_type) + && (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 + && SYMBOL_REFERENCES_LOCAL (info, h)) + { + 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->needs_copy) + { + 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. + On VxWorks, the _GLOBAL_OFFSET_TABLE_ symbol is not absolute: it + is relative to the ".got" section. */ + if (strcmp (h->root.root.string, "_DYNAMIC") == 0 + || (!htab->is_vxworks && h == htab->elf.hgot)) + 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 (const Elf_Internal_Rela *rela) +{ + switch (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 (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->size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + asection *s; + + bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + default: + continue; + + case DT_PLTGOT: + s = htab->sgotplt; + dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; + 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->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->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->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->size > 0) + { + if (info->shared) + { + memcpy (htab->splt->contents, elf_i386_pic_plt0_entry, + sizeof (elf_i386_pic_plt0_entry)); + memset (htab->splt->contents + sizeof (elf_i386_pic_plt0_entry), + htab->plt0_pad_byte, + PLT_ENTRY_SIZE - sizeof (elf_i386_pic_plt0_entry)); + } + else + { + memcpy (htab->splt->contents, elf_i386_plt0_entry, + sizeof(elf_i386_plt0_entry)); + memset (htab->splt->contents + sizeof (elf_i386_plt0_entry), + htab->plt0_pad_byte, + PLT_ENTRY_SIZE - sizeof (elf_i386_plt0_entry)); + 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); + + if (htab->is_vxworks) + { + Elf_Internal_Rela rel; + + /* Generate a relocation for _GLOBAL_OFFSET_TABLE_ + 4. + On IA32 we use REL relocations so the addend goes in + the PLT directly. */ + rel.r_offset = (htab->splt->output_section->vma + + htab->splt->output_offset + + 2); + rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, + htab->srelplt2->contents); + /* Generate a relocation for _GLOBAL_OFFSET_TABLE_ + 8. */ + rel.r_offset = (htab->splt->output_section->vma + + htab->splt->output_offset + + 8); + rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, + htab->srelplt2->contents + + sizeof (Elf32_External_Rel)); + } + } + + /* 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; + + /* Correct the .rel.plt.unloaded relocations. */ + if (htab->is_vxworks && !info->shared) + { + int num_plts = (htab->splt->size / PLT_ENTRY_SIZE) - 1; + unsigned char *p; + + p = htab->srelplt2->contents; + if (info->shared) + p += PLTRESOLVE_RELOCS_SHLIB * sizeof (Elf32_External_Rel); + else + p += PLTRESOLVE_RELOCS * sizeof (Elf32_External_Rel); + + for (; num_plts; num_plts--) + { + Elf_Internal_Rela rel; + bfd_elf32_swap_reloc_in (output_bfd, p, &rel); + rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, p); + p += sizeof (Elf32_External_Rel); + + bfd_elf32_swap_reloc_in (output_bfd, p, &rel); + rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_386_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, p); + p += sizeof (Elf32_External_Rel); + } + } + } + } + + if (htab->sgotplt) + { + /* Fill in the first three entries in the global offset table. */ + if (htab->sgotplt->size > 0) + { + bfd_put_32 (output_bfd, + (sdyn == NULL ? 0 + : sdyn->output_section->vma + sdyn->output_offset), + htab->sgotplt->contents); + bfd_put_32 (output_bfd, 0, htab->sgotplt->contents + 4); + bfd_put_32 (output_bfd, 0, htab->sgotplt->contents + 8); + } + + elf_section_data (htab->sgotplt->output_section)->this_hdr.sh_entsize = 4; + } + + if (htab->sgot && htab->sgot->size > 0) + elf_section_data (htab->sgot->output_section)->this_hdr.sh_entsize = 4; + + return TRUE; +} + +/* Return address for Ith PLT stub in section PLT, for relocation REL + or (bfd_vma) -1 if it should not be included. */ + +static bfd_vma +elf_i386_plt_sym_val (bfd_vma i, const asection *plt, + const arelent *rel ATTRIBUTE_UNUSED) +{ + return plt->vma + (i + 1) * PLT_ENTRY_SIZE; +} + + +#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 + +/* 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 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 +#define elf_backend_always_size_sections elf_i386_always_size_sections +#define elf_backend_plt_sym_val elf_i386_plt_sym_val + +#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 (bfd *abfd, + struct bfd_link_info *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" + +/* VxWorks support. */ + +#undef TARGET_LITTLE_SYM +#define TARGET_LITTLE_SYM bfd_elf32_i386_vxworks_vec +#undef TARGET_LITTLE_NAME +#define TARGET_LITTLE_NAME "elf32-i386-vxworks" + + +/* Like elf_i386_link_hash_table_create but with tweaks for VxWorks. */ + +static struct bfd_link_hash_table * +elf_i386_vxworks_link_hash_table_create (bfd *abfd) +{ + struct bfd_link_hash_table *ret; + struct elf_i386_link_hash_table *htab; + + ret = elf_i386_link_hash_table_create (abfd); + if (ret) + { + htab = (struct elf_i386_link_hash_table *) ret; + htab->is_vxworks = 1; + htab->plt0_pad_byte = 0x90; + } + + return ret; +} + + +#undef elf_backend_post_process_headers +#undef bfd_elf32_bfd_link_hash_table_create +#define bfd_elf32_bfd_link_hash_table_create \ + elf_i386_vxworks_link_hash_table_create +#undef elf_backend_add_symbol_hook +#define elf_backend_add_symbol_hook \ + elf_vxworks_add_symbol_hook +#undef elf_backend_link_output_symbol_hook +#define elf_backend_link_output_symbol_hook \ + elf_vxworks_link_output_symbol_hook +#undef elf_backend_emit_relocs +#define elf_backend_emit_relocs elf_vxworks_emit_relocs +#undef elf_backend_final_write_processing +#define elf_backend_final_write_processing \ + elf_vxworks_final_write_processing + +/* On VxWorks, we emit relocations against _PROCEDURE_LINKAGE_TABLE_, so + define it. */ +#undef elf_backend_want_plt_sym +#define elf_backend_want_plt_sym 1 + +#undef elf32_bed +#define elf32_bed elf32_i386_vxworks_bed + +#include "elf32-target.h" diff --git a/contrib/binutils-2.17/bfd/elf32.c b/contrib/binutils-2.17/bfd/elf32.c new file mode 100644 index 0000000000..6221f0ae1d --- /dev/null +++ b/contrib/binutils-2.17/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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define ARCH_SIZE 32 + +#include "elfcode.h" diff --git a/contrib/binutils-2.17/bfd/elf64-gen.c b/contrib/binutils-2.17/bfd/elf64-gen.c new file mode 100644 index 0000000000..49b8d9c552 --- /dev/null +++ b/contrib/binutils-2.17/bfd/elf64-gen.c @@ -0,0 +1,101 @@ +/* Generic support for 64-bit ELF + Copyright 1993, 1995, 1998, 1999, 2001, 2002, 2004, 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 (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 (bfd *abfd ATTRIBUTE_UNUSED, + arelent *bfd_reloc, + Elf_Internal_Rela *elf_reloc ATTRIBUTE_UNUSED) +{ + bfd_reloc->howto = &dummy; +} + +static void +check_for_relocs (bfd * abfd, asection * o, void * failed) +{ + if ((o->flags & SEC_RELOC) != 0) + { + Elf_Internal_Ehdr *ehdrp; + + ehdrp = elf_elfheader (abfd); + _bfd_error_handler (_("%B: Relocations in generic ELF (EM: %d)"), + abfd, ehdrp->e_machine); + + bfd_set_error (bfd_error_wrong_format); + * (bfd_boolean *) failed = TRUE; + } +} + +static bfd_boolean +elf64_generic_link_add_symbols (bfd *abfd, struct bfd_link_info *info) +{ + bfd_boolean failed = FALSE; + + /* Check if there are any relocations. */ + bfd_map_over_sections (abfd, check_for_relocs, & failed); + + if (failed) + return FALSE; + return bfd_elf_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.17/bfd/elf64-x86-64.c b/contrib/binutils-2.17/bfd/elf64-x86-64.c new file mode 100644 index 0000000000..9befd69c5d --- /dev/null +++ b/contrib/binutils-2.17/bfd/elf64-x86-64.c @@ -0,0 +1,3689 @@ +/* X86-64 specific support for 64-bit ELF + Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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, rightshift, size, bitsize, pc_relative, bitpos, complain_on_overflow, + special_function, name, partial_inplace, src_mask, dst_mask, pcrel_offset. */ +static reloc_howto_type x86_64_elf_howto_table[] = +{ + HOWTO(R_X86_64_NONE, 0, 0, 0, FALSE, 0, complain_overflow_dont, + 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_bitfield, + 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_signed, + 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), + HOWTO(R_X86_64_PC64, 0, 4, 64, TRUE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_X86_64_PC64", FALSE, MINUS_ONE, MINUS_ONE, + TRUE), + HOWTO(R_X86_64_GOTOFF64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_X86_64_GOTOFF64", + FALSE, MINUS_ONE, MINUS_ONE, FALSE), + HOWTO(R_X86_64_GOTPC32, 0, 2, 32, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_GOTPC32", + FALSE, 0xffffffff, 0xffffffff, TRUE), + HOWTO(R_X86_64_GOT64, 0, 4, 64, FALSE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_GOT64", FALSE, MINUS_ONE, MINUS_ONE, + FALSE), + HOWTO(R_X86_64_GOTPCREL64, 0, 4, 64, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_GOTPCREL64", FALSE, MINUS_ONE, + MINUS_ONE, TRUE), + HOWTO(R_X86_64_GOTPC64, 0, 4, 64, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_GOTPC64", + FALSE, MINUS_ONE, MINUS_ONE, TRUE), + HOWTO(R_X86_64_GOTPLT64, 0, 4, 64, FALSE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_GOTPLT64", FALSE, MINUS_ONE, + MINUS_ONE, FALSE), + HOWTO(R_X86_64_PLTOFF64, 0, 4, 64, FALSE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_PLTOFF64", FALSE, MINUS_ONE, + MINUS_ONE, FALSE), + EMPTY_HOWTO (32), + EMPTY_HOWTO (33), + HOWTO(R_X86_64_GOTPC32_TLSDESC, 0, 2, 32, TRUE, 0, + complain_overflow_bitfield, bfd_elf_generic_reloc, + "R_X86_64_GOTPC32_TLSDESC", + FALSE, 0xffffffff, 0xffffffff, TRUE), + HOWTO(R_X86_64_TLSDESC_CALL, 0, 0, 0, FALSE, 0, + complain_overflow_dont, bfd_elf_generic_reloc, + "R_X86_64_TLSDESC_CALL", + FALSE, 0, 0, FALSE), + HOWTO(R_X86_64_TLSDESC, 0, 4, 64, FALSE, 0, + complain_overflow_bitfield, bfd_elf_generic_reloc, + "R_X86_64_TLSDESC", + FALSE, MINUS_ONE, MINUS_ONE, FALSE), + + /* We have a gap in the reloc numbers here. + R_X86_64_standard counts the number up to this point, and + R_X86_64_vt_offset is the value to subtract from a reloc type of + R_X86_64_GNU_VT* to form an index into this table. */ +#define R_X86_64_standard (R_X86_64_TLSDESC + 1) +#define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard) + +/* 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_64_PCREL, R_X86_64_PC64, }, + { BFD_RELOC_X86_64_GOTOFF64, R_X86_64_GOTOFF64, }, + { BFD_RELOC_X86_64_GOTPC32, R_X86_64_GOTPC32, }, + { BFD_RELOC_X86_64_GOT64, R_X86_64_GOT64, }, + { BFD_RELOC_X86_64_GOTPCREL64,R_X86_64_GOTPCREL64, }, + { BFD_RELOC_X86_64_GOTPC64, R_X86_64_GOTPC64, }, + { BFD_RELOC_X86_64_GOTPLT64, R_X86_64_GOTPLT64, }, + { BFD_RELOC_X86_64_PLTOFF64, R_X86_64_PLTOFF64, }, + { BFD_RELOC_X86_64_GOTPC32_TLSDESC, R_X86_64_GOTPC32_TLSDESC, }, + { BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, }, + { BFD_RELOC_X86_64_TLSDESC, R_X86_64_TLSDESC, }, + { 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_rtype_to_howto (bfd *abfd, unsigned r_type) +{ + unsigned i; + + if (r_type < (unsigned int) R_X86_64_GNU_VTINHERIT + || r_type >= (unsigned int) R_X86_64_max) + { + if (r_type >= (unsigned int) R_X86_64_standard) + { + (*_bfd_error_handler) (_("%B: invalid relocation type %d"), + abfd, (int) r_type); + r_type = R_X86_64_NONE; + } + i = r_type; + } + else + i = r_type - (unsigned int) R_X86_64_vt_offset; + BFD_ASSERT (x86_64_elf_howto_table[i].type == r_type); + return &x86_64_elf_howto_table[i]; +} + +/* Given a BFD reloc type, return a HOWTO structure. */ +static reloc_howto_type * +elf64_x86_64_reloc_type_lookup (bfd *abfd, + 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 elf64_x86_64_rtype_to_howto (abfd, + x86_64_reloc_map[i].elf_reloc_val); + } + return 0; +} + +/* Given an x86_64 ELF reloc type, fill in an arelent structure. */ + +static void +elf64_x86_64_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, + Elf_Internal_Rela *dst) +{ + unsigned r_type; + + r_type = ELF64_R_TYPE (dst->r_info); + cache_ptr->howto = elf64_x86_64_rtype_to_howto (abfd, r_type); + BFD_ASSERT (r_type == cache_ptr->howto->type); +} + +/* Support for core dump NOTE sections. */ +static bfd_boolean +elf64_x86_64_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) +{ + int offset; + size_t 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; + size = 216; + + break; + } + + /* Make a ".reg/999" section. */ + return _bfd_elfcore_make_pseudosection (abfd, ".reg", + size, note->descpos + offset); +} + +static bfd_boolean +elf64_x86_64_grok_psinfo (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 +#define GOT_TLS_GDESC 4 +#define GOT_TLS_GD_BOTH_P(type) \ + ((type) == (GOT_TLS_GD | GOT_TLS_GDESC)) +#define GOT_TLS_GD_P(type) \ + ((type) == GOT_TLS_GD || GOT_TLS_GD_BOTH_P (type)) +#define GOT_TLS_GDESC_P(type) \ + ((type) == GOT_TLS_GDESC || GOT_TLS_GD_BOTH_P (type)) +#define GOT_TLS_GD_ANY_P(type) \ + (GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type)) + unsigned char tls_type; + + /* Offset of the GOTPLT entry reserved for the TLS descriptor, + starting at the end of the jump table. */ + bfd_vma tlsdesc_got; +}; + +#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; + + /* GOTPLT entries for TLS descriptors. */ + bfd_vma *local_tlsdesc_gotent; +}; + +#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) + +#define elf64_x86_64_local_tlsdesc_gotent(abfd) \ + (elf64_x86_64_tdata (abfd)->local_tlsdesc_gotent) + +/* 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; + + /* The offset into splt of the PLT entry for the TLS descriptor + resolver. Special values are 0, if not necessary (or not found + to be necessary yet), and -1 if needed but not determined + yet. */ + bfd_vma tlsdesc_plt; + /* The offset into sgot of the GOT entry used by the PLT entry + above. */ + bfd_vma tlsdesc_got; + + union { + bfd_signed_vma refcount; + bfd_vma offset; + } tls_ld_got; + + /* The amount of space used by the jump slots in the GOT. */ + bfd_vma sgotplt_jump_table_size; + + /* 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)) + +#define elf64_x86_64_compute_jump_table_size(htab) \ + ((htab)->srelplt->reloc_count * GOT_ENTRY_SIZE) + +/* Create an entry in an x86-64 ELF linker hash table. */ + +static struct bfd_hash_entry * +link_hash_newfunc (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; + eh->tlsdesc_got = (bfd_vma) -1; + } + + return entry; +} + +/* Create an X86-64 ELF linker hash table. */ + +static struct bfd_link_hash_table * +elf64_x86_64_link_hash_table_create (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, + sizeof (struct elf64_x86_64_link_hash_entry))) + { + 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->tlsdesc_plt = 0; + ret->tlsdesc_got = 0; + ret->tls_ld_got.refcount = 0; + ret->sgotplt_jump_table_size = 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 (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_with_flags (dynobj, ".rela.got", + (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_LINKER_CREATED + | SEC_READONLY)); + if (htab->srelgot == NULL + || ! 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 (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 (struct bfd_link_info *info, + struct elf_link_hash_entry *dir, + struct elf_link_hash_entry *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; + + /* Add reloc counts against the indirect sym to the direct sym + list. Merge any entries against the same section. */ + for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) + { + struct 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->dynamic_adjusted) + { + /* If called to transfer flags for a weakdef during processing + of elf_adjust_dynamic_symbol, don't copy non_got_ref. + We clear it ourselves for ELIMINATE_COPY_RELOCS. */ + dir->ref_dynamic |= ind->ref_dynamic; + dir->ref_regular |= ind->ref_regular; + dir->ref_regular_nonweak |= ind->ref_regular_nonweak; + dir->needs_plt |= ind->needs_plt; + dir->pointer_equality_needed |= ind->pointer_equality_needed; + } + else + _bfd_elf_link_hash_copy_indirect (info, dir, ind); +} + +static bfd_boolean +elf64_x86_64_mkobject (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 (bfd *abfd) +{ + /* 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 (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_GOTPC32_TLSDESC: + case R_X86_64_TLSDESC_CALL: + 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 (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->relocatable) + 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) (_("%B: bad symbol index: %d"), + abfd, r_symndx); + return FALSE; + } + + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + } + + 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) + (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"), + abfd, + x86_64_elf_howto_table[r_type].name, + (h) ? h->root.root.string : "a local symbol"); + 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: + case R_X86_64_GOT64: + case R_X86_64_GOTPCREL64: + case R_X86_64_GOTPLT64: + case R_X86_64_GOTPC32_TLSDESC: + case R_X86_64_TLSDESC_CALL: + /* 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; + case R_X86_64_GOTPC32_TLSDESC: + case R_X86_64_TLSDESC_CALL: + tls_type = GOT_TLS_GDESC; break; + } + + if (h != NULL) + { + if (r_type == R_X86_64_GOTPLT64) + { + /* This relocation indicates that we also need + a PLT entry, as this is a function. We don't need + a PLT entry for local symbols. */ + h->needs_plt = 1; + h->plt.refcount += 1; + } + h->got.refcount += 1; + old_tls_type = 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 (bfd_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_tlsdesc_gotent (abfd) + = (bfd_vma *) (local_got_refcounts + symtab_hdr->sh_info); + elf64_x86_64_local_got_tls_type (abfd) + = (char *) (local_got_refcounts + 2 * 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 + && (! GOT_TLS_GD_ANY_P (old_tls_type) + || tls_type != GOT_TLS_IE)) + { + if (old_tls_type == GOT_TLS_IE && GOT_TLS_GD_ANY_P (tls_type)) + tls_type = old_tls_type; + else if (GOT_TLS_GD_ANY_P (old_tls_type) + && GOT_TLS_GD_ANY_P (tls_type)) + tls_type |= old_tls_type; + else + { + (*_bfd_error_handler) + (_("%B: %s' accessed both as normal and thread local symbol"), + 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_GOTOFF64: + case R_X86_64_GOTPC32: + case R_X86_64_GOTPC64: + 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->needs_plt = 1; + h->plt.refcount += 1; + break; + + case R_X86_64_PLTOFF64: + /* This tries to form the 'address' of a function relative + to GOT. For global symbols we need a PLT entry. */ + if (h != NULL) + { + h->needs_plt = 1; + h->plt.refcount += 1; + } + goto create_got; + + 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) + (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"), + abfd, + x86_64_elf_howto_table[r_type].name, + (h) ? h->root.root.string : "a local symbol"); + 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_PC64: + 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->non_got_ref = 1; + + /* We may need a .plt entry if the function this reloc + refers to is in a shared lib. */ + h->plt.refcount += 1; + if (r_type != R_X86_64_PC32 && r_type != R_X86_64_PC64) + h->pointer_equality_needed = 1; + } + + /* If we are creating a shared library, and this is a reloc + against a global symbol, or a non PC relative reloc + against a local symbol, then we need to copy the reloc + into the shared library. However, if we are linking with + -Bsymbolic, we do not need to copy a reloc against a + global symbol which is defined in an object we are + including in the link (i.e., DEF_REGULAR is set). At + this point we have not seen all the input files, so it is + possible that DEF_REGULAR is not set now but will be set + later (it is never cleared). In case of a weak definition, + DEF_REGULAR may be cleared later by a strong definition in + a shared library. We account for that possibility below by + storing information in the relocs_copied field of the hash + table entry. A similar situation occurs when creating + shared libraries and symbol visibility changes render the + symbol local. + + If on the other hand, we are creating an executable, we + may need to keep relocations for symbols satisfied by a + dynamic library if we manage to avoid copy relocs for the + symbol. */ + if ((info->shared + && (sec->flags & SEC_ALLOC) != 0 + && (((r_type != R_X86_64_PC8) + && (r_type != R_X86_64_PC16) + && (r_type != R_X86_64_PC32) + && (r_type != R_X86_64_PC64)) + || (h != NULL + && (! info->symbolic + || h->root.type == bfd_link_hash_defweak + || !h->def_regular)))) + || (ELIMINATE_COPY_RELOCS + && !info->shared + && (sec->flags & SEC_ALLOC) != 0 + && h != NULL + && (h->root.type == bfd_link_hash_defweak + || !h->def_regular))) + { + 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) + (_("%B: bad relocation section name `%s\'"), + 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; + + flags = (SEC_HAS_CONTENTS | SEC_READONLY + | SEC_IN_MEMORY | SEC_LINKER_CREATED); + if ((sec->flags & SEC_ALLOC) != 0) + flags |= SEC_ALLOC | SEC_LOAD; + sreloc = bfd_make_section_with_flags (dynobj, + name, + flags); + if (sreloc == NULL + || ! 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 + { + void **vpp; + /* 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; + + /* Beware of type punned pointers vs strict aliasing + rules. */ + vpp = &(elf_section_data (s)->local_dynrel); + head = (struct elf64_x86_64_dyn_relocs **)vpp; + } + + 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 + || r_type == R_X86_64_PC64) + 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_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) + return FALSE; + break; + + /* This relocation describes which C++ vtable entries are actually + used. Record for later use during GC. */ + case R_X86_64_GNU_VTENTRY: + if (!bfd_elf_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 (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 (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]; + 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; + 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_GOTPC32_TLSDESC: + case R_X86_64_TLSDESC_CALL: + case R_X86_64_GOTTPOFF: + case R_X86_64_GOT32: + case R_X86_64_GOTPCREL: + case R_X86_64_GOT64: + case R_X86_64_GOTPCREL64: + case R_X86_64_GOTPLT64: + if (h != NULL) + { + if (r_type == R_X86_64_GOTPLT64 && h->plt.refcount > 0) + h->plt.refcount -= 1; + if (h->got.refcount > 0) + h->got.refcount -= 1; + } + 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: + case R_X86_64_PC64: + if (info->shared) + break; + /* Fall thru */ + + case R_X86_64_PLT32: + case R_X86_64_PLTOFF64: + 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 (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->needs_plt) + { + if (h->plt.refcount <= 0 + || SYMBOL_CALLS_LOCAL (info, h) + || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT + && h->root.type == bfd_link_hash_undefweak)) + { + /* 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->needs_plt = 0; + } + + 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->u.weakdef != NULL) + { + BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined + || h->u.weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->u.weakdef->root.u.def.section; + h->root.u.def.value = h->u.weakdef->root.u.def.value; + if (ELIMINATE_COPY_RELOCS || info->nocopyreloc) + h->non_got_ref = h->u.weakdef->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->non_got_ref) + return TRUE; + + /* If -z nocopyreloc was given, we won't generate them either. */ + if (info->nocopyreloc) + { + h->non_got_ref = 0; + return TRUE; + } + + 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->non_got_ref = 0; + return TRUE; + } + } + + if (h->size == 0) + { + (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"), + h->root.root.string); + 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->size += sizeof (Elf64_External_Rela); + h->needs_copy = 1; + } + + /* We need to figure out the alignment required for this symbol. I + have no idea how ELF linkers handle this. 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->size = BFD_ALIGN (s->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->size; + + /* Increment the section size to make room for the symbol. */ + s->size += h->size; + + return TRUE; +} + +/* Allocate space in .plt, .got and associated reloc sections for + dynamic relocs. */ + +static bfd_boolean +allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) +{ + struct bfd_link_info *info; + struct 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->forced_local) + { + if (! bfd_elf_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->size == 0) + s->size += PLT_ENTRY_SIZE; + + h->plt.offset = s->size; + + /* If this symbol is not defined in a regular file, and we are + not generating a shared library, then set the symbol to this + location in the .plt. This is required to make function + pointers compare as equal between the normal executable and + the shared library. */ + if (! info->shared + && !h->def_regular) + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } + + /* Make room for this entry. */ + s->size += PLT_ENTRY_SIZE; + + /* We also need to make an entry in the .got.plt section, which + will be placed in the .got section by the linker script. */ + htab->sgotplt->size += GOT_ENTRY_SIZE; + + /* We also need to make an entry in the .rela.plt section. */ + htab->srelplt->size += sizeof (Elf64_External_Rela); + htab->srelplt->reloc_count++; + } + else + { + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + } + else + { + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + + eh = (struct elf64_x86_64_link_hash_entry *) h; + eh->tlsdesc_got = (bfd_vma) -1; + + /* 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->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + if (GOT_TLS_GDESC_P (tls_type)) + { + eh->tlsdesc_got = htab->sgotplt->size + - elf64_x86_64_compute_jump_table_size (htab); + htab->sgotplt->size += 2 * GOT_ENTRY_SIZE; + h->got.offset = (bfd_vma) -2; + } + if (! GOT_TLS_GDESC_P (tls_type) + || GOT_TLS_GD_P (tls_type)) + { + s = htab->sgot; + h->got.offset = s->size; + s->size += GOT_ENTRY_SIZE; + if (GOT_TLS_GD_P (tls_type)) + s->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 ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1) + || tls_type == GOT_TLS_IE) + htab->srelgot->size += sizeof (Elf64_External_Rela); + else if (GOT_TLS_GD_P (tls_type)) + htab->srelgot->size += 2 * sizeof (Elf64_External_Rela); + else if (! GOT_TLS_GDESC_P (tls_type) + && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak) + && (info->shared + || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))) + htab->srelgot->size += sizeof (Elf64_External_Rela); + if (GOT_TLS_GDESC_P (tls_type)) + { + htab->srelplt->size += sizeof (Elf64_External_Rela); + htab->tlsdesc_plt = (bfd_vma) -1; + } + } + else + h->got.offset = (bfd_vma) -1; + + if (eh->dyn_relocs == NULL) + return TRUE; + + /* In the shared -Bsymbolic case, discard space allocated for + dynamic pc-relative relocs against symbols which turn out to be + defined in regular objects. For the normal shared case, discard + space for pc-relative relocs that have become local due to symbol + visibility changes. */ + + if (info->shared) + { + /* Relocs that use pc_count are those that appear on a call + insn, or certain REL relocs that can generated via assembly. + We want calls to protected symbols to resolve directly to the + function rather than going via the plt. If people want + function pointer comparisons to work as expected then they + should avoid writing weird assembly. */ + if (SYMBOL_CALLS_LOCAL (info, h)) + { + 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; + } + } + + /* Also discard relocs on undefined weak syms with non-default + visibility. */ + if (eh->dyn_relocs != NULL + && h->root.type == bfd_link_hash_undefweak) + { + if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) + eh->dyn_relocs = NULL; + + /* Make sure undefined weak symbols are output as a dynamic + symbol in PIEs. */ + else if (h->dynindx == -1 + && !h->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + } + } + else 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->non_got_ref + && ((h->def_dynamic + && !h->def_regular) + || (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->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + /* If that succeeded, we know we'll be keeping all the + relocs. */ + if (h->dynindx != -1) + goto keep; + } + + eh->dyn_relocs = NULL; + + keep: ; + } + + /* Finally, allocate space. */ + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + asection *sreloc = elf_section_data (p->sec)->sreloc; + sreloc->size += p->count * sizeof (Elf64_External_Rela); + } + + return TRUE; +} + +/* Find any dynamic relocs that apply to read-only sections. */ + +static bfd_boolean +readonly_dynrelocs (struct elf_link_hash_entry *h, void * inf) +{ + struct 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 (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->executable) + { + s = bfd_get_section_by_name (dynobj, ".interp"); + if (s == NULL) + abort (); + s->size = sizeof ELF_DYNAMIC_INTERPRETER; + s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; + } + } + + /* Set up .got offsets for local syms, and space for local dynamic + relocs. */ + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + { + bfd_signed_vma *local_got; + bfd_signed_vma *end_local_got; + char *local_tls_type; + bfd_vma *local_tlsdesc_gotent; + 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->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); + local_tlsdesc_gotent = elf64_x86_64_local_tlsdesc_gotent (ibfd); + s = htab->sgot; + srel = htab->srelgot; + for (; local_got < end_local_got; + ++local_got, ++local_tls_type, ++local_tlsdesc_gotent) + { + *local_tlsdesc_gotent = (bfd_vma) -1; + if (*local_got > 0) + { + if (GOT_TLS_GDESC_P (*local_tls_type)) + { + *local_tlsdesc_gotent = htab->sgotplt->size + - elf64_x86_64_compute_jump_table_size (htab); + htab->sgotplt->size += 2 * GOT_ENTRY_SIZE; + *local_got = (bfd_vma) -2; + } + if (! GOT_TLS_GDESC_P (*local_tls_type) + || GOT_TLS_GD_P (*local_tls_type)) + { + *local_got = s->size; + s->size += GOT_ENTRY_SIZE; + if (GOT_TLS_GD_P (*local_tls_type)) + s->size += GOT_ENTRY_SIZE; + } + if (info->shared + || GOT_TLS_GD_ANY_P (*local_tls_type) + || *local_tls_type == GOT_TLS_IE) + { + if (GOT_TLS_GDESC_P (*local_tls_type)) + { + htab->srelplt->size += sizeof (Elf64_External_Rela); + htab->tlsdesc_plt = (bfd_vma) -1; + } + if (! GOT_TLS_GDESC_P (*local_tls_type) + || GOT_TLS_GD_P (*local_tls_type)) + srel->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->size; + htab->sgot->size += 2 * GOT_ENTRY_SIZE; + htab->srelgot->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); + + /* For every jump slot reserved in the sgotplt, reloc_count is + incremented. However, when we reserve space for TLS descriptors, + it's not incremented, so in order to compute the space reserved + for them, it suffices to multiply the reloc count by the jump + slot size. */ + if (htab->srelplt) + htab->sgotplt_jump_table_size + = elf64_x86_64_compute_jump_table_size (htab); + + if (htab->tlsdesc_plt) + { + /* If we're not using lazy TLS relocations, don't generate the + PLT and GOT entries they require. */ + if ((info->flags & DF_BIND_NOW)) + htab->tlsdesc_plt = 0; + else + { + htab->tlsdesc_got = htab->sgot->size; + htab->sgot->size += GOT_ENTRY_SIZE; + /* Reserve room for the initial entry. + FIXME: we could probably do away with it in this case. */ + if (htab->splt->size == 0) + htab->splt->size += PLT_ENTRY_SIZE; + htab->tlsdesc_plt = htab->splt->size; + htab->splt->size += PLT_ENTRY_SIZE; + } + } + + /* We now have determined the sizes of the various dynamic sections. + Allocate memory for them. */ + relocs = FALSE; + for (s = dynobj->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_LINKER_CREATED) == 0) + continue; + + if (s == htab->splt + || s == htab->sgot + || s == htab->sgotplt + || s == htab->sdynbss) + { + /* Strip this section if we don't need it; see the + comment below. */ + } + else if (strncmp (bfd_get_section_name (dynobj, s), ".rela", 5) == 0) + { + if (s->size != 0 && s != htab->srelplt) + relocs = TRUE; + + /* We use the reloc_count field as a counter if we need + to copy relocs into the output file. */ + if (s != htab->srelplt) + s->reloc_count = 0; + } + else + { + /* It's not one of our sections, so don't allocate space. */ + continue; + } + + if (s->size == 0) + { + /* If we don't need this section, strip it from the + output file. This is mostly to handle .rela.bss and + .rela.plt. We must create both sections in + create_dynamic_sections, because they must be created + before the linker maps input sections to output + sections. The linker does that before + adjust_dynamic_symbol is called, and it is that + function which decides whether anything needs to go + into these sections. */ + + s->flags |= SEC_EXCLUDE; + continue; + } + + if ((s->flags & SEC_HAS_CONTENTS) == 0) + continue; + + /* Allocate memory for the section contents. We use bfd_zalloc + here in case unused entries are not reclaimed before the + section's contents are written out. This should not happen, + but this way if it does, we get a R_X86_64_NONE reloc instead + of garbage. */ + s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->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_elf_add_dynamic_entry (info, TAG, VAL) + + if (info->executable) + { + if (!add_dynamic_entry (DT_DEBUG, 0)) + return FALSE; + } + + if (htab->splt->size != 0) + { + if (!add_dynamic_entry (DT_PLTGOT, 0) + || !add_dynamic_entry (DT_PLTRELSZ, 0) + || !add_dynamic_entry (DT_PLTREL, DT_RELA) + || !add_dynamic_entry (DT_JMPREL, 0)) + return FALSE; + + if (htab->tlsdesc_plt + && (!add_dynamic_entry (DT_TLSDESC_PLT, 0) + || !add_dynamic_entry (DT_TLSDESC_GOT, 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; +} + +static bfd_boolean +elf64_x86_64_always_size_sections (bfd *output_bfd, + struct bfd_link_info *info) +{ + asection *tls_sec = elf_hash_table (info)->tls_sec; + + if (tls_sec) + { + struct elf_link_hash_entry *tlsbase; + + tlsbase = elf_link_hash_lookup (elf_hash_table (info), + "_TLS_MODULE_BASE_", + FALSE, FALSE, FALSE); + + if (tlsbase && tlsbase->type == STT_TLS) + { + struct bfd_link_hash_entry *bh = NULL; + const struct elf_backend_data *bed + = get_elf_backend_data (output_bfd); + + if (!(_bfd_generic_link_add_one_symbol + (info, output_bfd, "_TLS_MODULE_BASE_", BSF_LOCAL, + tls_sec, 0, NULL, FALSE, + bed->collect, &bh))) + return FALSE; + tlsbase = (struct elf_link_hash_entry *)bh; + tlsbase->def_regular = 1; + tlsbase->other = STV_HIDDEN; + (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE); + } + } + + 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 (struct bfd_link_info *info) +{ + /* If tls_sec is NULL, we should have signalled an error already. */ + if (elf_hash_table (info)->tls_sec == NULL) + return 0; + return elf_hash_table (info)->tls_sec->vma; +} + +/* Return the relocation value for @tpoff relocation + if STT_TLS virtual address is ADDRESS. */ + +static bfd_vma +tpoff (struct bfd_link_info *info, bfd_vma address) +{ + struct elf_link_hash_table *htab = elf_hash_table (info); + + /* If tls_segment is NULL, we should have signalled an error already. */ + if (htab->tls_sec == NULL) + return 0; + return address - htab->tls_size - htab->tls_sec->vma; +} + +/* Is the instruction before OFFSET in CONTENTS a 32bit relative + branch? */ + +static bfd_boolean +is_32bit_relative_branch (bfd_byte *contents, bfd_vma offset) +{ + /* Opcode Instruction + 0xe8 call + 0xe9 jump + 0x0f 0x8x conditional jump */ + return ((offset > 0 + && (contents [offset - 1] == 0xe8 + || contents [offset - 1] == 0xe9)) + || (offset > 1 + && contents [offset - 2] == 0x0f + && (contents [offset - 1] & 0xf0) == 0x80)); +} + +/* Relocate an x86_64 ELF section. */ + +static bfd_boolean +elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, + bfd *input_bfd, asection *input_section, + bfd_byte *contents, Elf_Internal_Rela *relocs, + Elf_Internal_Sym *local_syms, + asection **local_sections) +{ + 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; + bfd_vma *local_tlsdesc_gotents; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + + if (info->relocatable) + 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); + local_tlsdesc_gotents = elf64_x86_64_local_tlsdesc_gotent (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, offplt; + 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 + { + bfd_boolean warned; + + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, + r_symndx, symtab_hdr, sym_hashes, + h, sec, relocation, + unresolved_reloc, warned); + } + /* When generating a shared object, the relocations handled here are + copied into the output file to be resolved at run time. */ + switch (r_type) + { + asection *base_got; + case R_X86_64_GOT32: + case R_X86_64_GOT64: + /* Relocation is to the entry for this symbol in the global + offset table. */ + case R_X86_64_GOTPCREL: + case R_X86_64_GOTPCREL64: + /* Use global offset table entry as symbol value. */ + case R_X86_64_GOTPLT64: + /* This is the same as GOT64 for relocation purposes, but + indicates the existence of a PLT entry. The difficulty is, + that we must calculate the GOT slot offset from the PLT + offset, if this symbol got a PLT entry (it was global). + Additionally if it's computed from the PLT entry, then that + GOT offset is relative to .got.plt, not to .got. */ + base_got = htab->sgot; + + if (htab->sgot == NULL) + abort (); + + if (h != NULL) + { + bfd_boolean dyn; + + off = h->got.offset; + if (h->needs_plt + && h->plt.offset != (bfd_vma)-1 + && off == (bfd_vma)-1) + { + /* We can't use h->got.offset here to save + state, or even just remember the offset, as + finish_dynamic_symbol would use that as offset into + .got. */ + bfd_vma plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; + off = (plt_index + 3) * GOT_ENTRY_SIZE; + base_got = htab->sgotplt; + } + + dyn = htab->elf.dynamic_sections_created; + + if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) + || (info->shared + && SYMBOL_REFERENCES_LOCAL (info, h)) + || (ELF_ST_VISIBILITY (h->other) + && h->root.type == bfd_link_hash_undefweak)) + { + /* 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, + base_got->contents + off); + /* Note that this is harmless for the GOTPLT64 case, + as -1 | 1 still is -1. */ + 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, + base_got->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 = (base_got->output_section->vma + + base_got->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 = base_got->output_section->vma + + base_got->output_offset + off; + if (r_type != R_X86_64_GOTPCREL && r_type != R_X86_64_GOTPCREL64) + relocation -= htab->sgotplt->output_section->vma + - htab->sgotplt->output_offset; + + break; + + case R_X86_64_GOTOFF64: + /* Relocation is relative to the start of the global offset + table. */ + + /* Check to make sure it isn't a protected function symbol + for shared library since it may not be local when used + as function address. */ + if (info->shared + && h + && h->def_regular + && h->type == STT_FUNC + && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) + { + (*_bfd_error_handler) + (_("%B: relocation R_X86_64_GOTOFF64 against protected function `%s' can not be used when making a shared object"), + input_bfd, h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + /* Note that sgot is not involved in this + calculation. We always want the start of .got.plt. 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->sgotplt->output_section->vma + + htab->sgotplt->output_offset; + break; + + case R_X86_64_GOTPC32: + case R_X86_64_GOTPC64: + /* Use global offset table as symbol value. */ + relocation = htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset; + unresolved_reloc = FALSE; + break; + + case R_X86_64_PLTOFF64: + /* Relocation is PLT entry relative to GOT. For local + symbols it's the symbol itself relative to GOT. */ + if (h != NULL + /* See PLT32 handling. */ + && h->plt.offset != (bfd_vma) -1 + && htab->splt != NULL) + { + relocation = (htab->splt->output_section->vma + + htab->splt->output_offset + + h->plt.offset); + unresolved_reloc = FALSE; + } + + relocation -= htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset; + 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: + if (info->shared + && !SYMBOL_REFERENCES_LOCAL (info, h) + && (input_section->flags & SEC_ALLOC) != 0 + && (input_section->flags & SEC_READONLY) != 0 + && (!h->def_regular + || r_type != R_X86_64_PC32 + || h->type != STT_FUNC + || ELF_ST_VISIBILITY (h->other) != STV_PROTECTED + || !is_32bit_relative_branch (contents, + rel->r_offset))) + { + if (h->def_regular + && r_type == R_X86_64_PC32 + && h->type == STT_FUNC + && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) + (*_bfd_error_handler) + (_("%B: relocation R_X86_64_PC32 against protected function `%s' can not be used when making a shared object"), + input_bfd, h->root.root.string); + else + (*_bfd_error_handler) + (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"), + input_bfd, x86_64_elf_howto_table[r_type].name, + h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + /* Fall through. */ + + case R_X86_64_8: + case R_X86_64_16: + case R_X86_64_32: + case R_X86_64_PC64: + 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 + && (h == NULL + || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak) + && ((r_type != R_X86_64_PC8 + && r_type != R_X86_64_PC16 + && r_type != R_X86_64_PC32 + && r_type != R_X86_64_PC64) + || !SYMBOL_CALLS_LOCAL (info, h))) + || (ELIMINATE_COPY_RELOCS + && !info->shared + && h != NULL + && h->dynindx != -1 + && !h->non_got_ref + && ((h->def_dynamic + && !h->def_regular) + || h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined))) + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + bfd_boolean skip, 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 + || r_type == R_X86_64_PC64 + || !info->shared + || !info->symbolic + || !h->def_regular)) + { + 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 (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_GOTPC32_TLSDESC: + case R_X86_64_TLSDESC_CALL: + 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 + || r_type == R_X86_64_GOTPC32_TLSDESC + || r_type == R_X86_64_TLSDESC_CALL) + { + 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->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 if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC) + { + /* GDesc -> LE transition. + It's originally something like: + leaq x@tlsdesc(%rip), %rax + + Change it to: + movl $x@tpoff, %rax + + Registers other than %rax may be set up here. */ + + unsigned int val, type, type2; + bfd_vma roff; + + /* First, make sure it's a leaq adding rip to a + 32-bit offset into any register, although it's + probably almost always going to be rax. */ + roff = rel->r_offset; + BFD_ASSERT (roff >= 3); + type = bfd_get_8 (input_bfd, contents + roff - 3); + BFD_ASSERT ((type & 0xfb) == 0x48); + type2 = bfd_get_8 (input_bfd, contents + roff - 2); + BFD_ASSERT (type2 == 0x8d); + val = bfd_get_8 (input_bfd, contents + roff - 1); + BFD_ASSERT ((val & 0xc7) == 0x05); + BFD_ASSERT (roff + 4 <= input_section->size); + + /* Now modify the instruction as appropriate. */ + bfd_put_8 (output_bfd, 0x48 | ((type >> 2) & 1), + contents + roff - 3); + bfd_put_8 (output_bfd, 0xc7, contents + roff - 2); + bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7), + contents + roff - 1); + bfd_put_32 (output_bfd, tpoff (info, relocation), + contents + roff); + continue; + } + else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSDESC_CALL) + { + /* GDesc -> LE transition. + It's originally: + call *(%rax) + Turn it into: + nop; nop. */ + + unsigned int val, type; + bfd_vma roff; + + /* First, make sure it's a call *(%rax). */ + roff = rel->r_offset; + BFD_ASSERT (roff + 2 <= input_section->size); + type = bfd_get_8 (input_bfd, contents + roff); + BFD_ASSERT (type == 0xff); + val = bfd_get_8 (input_bfd, contents + roff + 1); + BFD_ASSERT (val == 0x10); + + /* Now modify the instruction as appropriate. */ + bfd_put_8 (output_bfd, 0x90, contents + roff); + bfd_put_8 (output_bfd, 0x90, contents + roff + 1); + 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->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; + offplt = elf64_x86_64_hash_entry (h)->tlsdesc_got; + } + else + { + if (local_got_offsets == NULL) + abort (); + + off = local_got_offsets[r_symndx]; + offplt = local_tlsdesc_gotents[r_symndx]; + } + + if ((off & 1) != 0) + off &= ~1; + else + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + int dr_type, indx; + asection *sreloc; + + if (htab->srelgot == NULL) + abort (); + + indx = h && h->dynindx != -1 ? h->dynindx : 0; + + if (GOT_TLS_GDESC_P (tls_type)) + { + outrel.r_info = ELF64_R_INFO (indx, R_X86_64_TLSDESC); + BFD_ASSERT (htab->sgotplt_jump_table_size + offplt + + 2 * GOT_ENTRY_SIZE <= htab->sgotplt->size); + outrel.r_offset = (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + offplt + + htab->sgotplt_jump_table_size); + sreloc = htab->srelplt; + loc = sreloc->contents; + loc += sreloc->reloc_count++ + * sizeof (Elf64_External_Rela); + BFD_ASSERT (loc + sizeof (Elf64_External_Rela) + <= sreloc->contents + sreloc->size); + if (indx == 0) + outrel.r_addend = relocation - dtpoff_base (info); + else + outrel.r_addend = 0; + bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); + } + + sreloc = htab->srelgot; + + outrel.r_offset = (htab->sgot->output_section->vma + + htab->sgot->output_offset + off); + + if (GOT_TLS_GD_P (tls_type)) + dr_type = R_X86_64_DTPMOD64; + else if (GOT_TLS_GDESC_P (tls_type)) + goto dr_done; + 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 + || dr_type == R_X86_64_TLSDESC) && indx == 0) + outrel.r_addend = relocation - dtpoff_base (info); + outrel.r_info = ELF64_R_INFO (indx, dr_type); + + loc = sreloc->contents; + loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela); + BFD_ASSERT (loc + sizeof (Elf64_External_Rela) + <= sreloc->contents + sreloc->size); + bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); + + if (GOT_TLS_GD_P (tls_type)) + { + 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; + sreloc->reloc_count++; + loc += sizeof (Elf64_External_Rela); + BFD_ASSERT (loc + sizeof (Elf64_External_Rela) + <= sreloc->contents + sreloc->size); + bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); + } + } + + dr_done: + if (h != NULL) + h->got.offset |= 1; + else + local_got_offsets[r_symndx] |= 1; + } + + if (off >= (bfd_vma) -2 + && ! GOT_TLS_GDESC_P (tls_type)) + abort (); + if (r_type == ELF64_R_TYPE (rel->r_info)) + { + if (r_type == R_X86_64_GOTPC32_TLSDESC + || r_type == R_X86_64_TLSDESC_CALL) + relocation = htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + offplt + htab->sgotplt_jump_table_size; + else + relocation = htab->sgot->output_section->vma + + htab->sgot->output_offset + off; + unresolved_reloc = FALSE; + } + else 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->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->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; + } + else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC) + { + /* GDesc -> IE transition. + It's originally something like: + leaq x@tlsdesc(%rip), %rax + + Change it to: + movq x@gottpoff(%rip), %rax # before nop; nop + + Registers other than %rax may be set up here. */ + + unsigned int val, type, type2; + bfd_vma roff; + + /* First, make sure it's a leaq adding rip to a 32-bit + offset into any register, although it's probably + almost always going to be rax. */ + roff = rel->r_offset; + BFD_ASSERT (roff >= 3); + type = bfd_get_8 (input_bfd, contents + roff - 3); + BFD_ASSERT ((type & 0xfb) == 0x48); + type2 = bfd_get_8 (input_bfd, contents + roff - 2); + BFD_ASSERT (type2 == 0x8d); + val = bfd_get_8 (input_bfd, contents + roff - 1); + BFD_ASSERT ((val & 0xc7) == 0x05); + BFD_ASSERT (roff + 4 <= input_section->size); + + /* Now modify the instruction as appropriate. */ + /* To turn a leaq into a movq in the form we use it, it + suffices to change the second byte from 0x8d to + 0x8b. */ + bfd_put_8 (output_bfd, 0x8b, contents + roff - 2); + + bfd_put_32 (output_bfd, + htab->sgot->output_section->vma + + htab->sgot->output_offset + off + - rel->r_offset + - input_section->output_section->vma + - input_section->output_offset + - 4, + contents + roff); + continue; + } + else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSDESC_CALL) + { + /* GDesc -> IE transition. + It's originally: + call *(%rax) + + Change it to: + nop; nop. */ + + unsigned int val, type; + bfd_vma roff; + + /* First, make sure it's a call *(%eax). */ + roff = rel->r_offset; + BFD_ASSERT (roff + 2 <= input_section->size); + type = bfd_get_8 (input_bfd, contents + roff); + BFD_ASSERT (type == 0xff); + val = bfd_get_8 (input_bfd, contents + roff + 1); + BFD_ASSERT (val == 0x10); + + /* Now modify the instruction as appropriate. */ + bfd_put_8 (output_bfd, 0x90, contents + roff); + bfd_put_8 (output_bfd, 0x90, contents + roff + 1); + + continue; + } + else + BFD_ASSERT (FALSE); + 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->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->def_dynamic)) + (*_bfd_error_handler) + (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"), + input_bfd, + input_section, + (long) rel->r_offset, + howto->name, + 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 (h != NULL + && h->root.type == bfd_link_hash_undefweak + && howto->pc_relative) + /* Ignore reloc overflow on branches to undefweak syms. */ + continue; + + if (! ((*info->callbacks->reloc_overflow) + (info, (h ? &h->root : NULL), name, howto->name, + (bfd_vma) 0, input_bfd, input_section, + rel->r_offset))) + return FALSE; + } + else + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx): reloc against `%s': error %d"), + 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 (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->def_regular) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value if there were any + relocations where pointer equality matters (this is a clue + for the dynamic linker, to make function pointer + comparisons work between an application and shared + library), otherwise set it to zero. If a function is only + called from a binary, there is no need to slow down + shared libraries because of that. */ + sym->st_shndx = SHN_UNDEF; + if (!h->pointer_equality_needed) + sym->st_value = 0; + } + } + + if (h->got.offset != (bfd_vma) -1 + && ! GOT_TLS_GD_ANY_P (elf64_x86_64_hash_entry (h)->tls_type) + && 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 + && SYMBOL_REFERENCES_LOCAL (info, h)) + { + 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->needs_copy) + { + 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 + || h == htab->elf.hgot) + 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 (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 (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->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: + s = htab->sgotplt; + dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; + break; + + case DT_JMPREL: + dyn.d_un.d_ptr = htab->srelplt->output_section->vma; + break; + + case DT_PLTRELSZ: + s = htab->srelplt->output_section; + dyn.d_un.d_val = s->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; + dyn.d_un.d_val -= s->size; + } + break; + + case DT_TLSDESC_PLT: + s = htab->splt; + dyn.d_un.d_ptr = s->output_section->vma + s->output_offset + + htab->tlsdesc_plt; + break; + + case DT_TLSDESC_GOT: + s = htab->sgot; + dyn.d_un.d_ptr = s->output_section->vma + s->output_offset + + htab->tlsdesc_got; + 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->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->tlsdesc_plt) + { + bfd_put_64 (output_bfd, (bfd_vma) 0, + htab->sgot->contents + htab->tlsdesc_got); + + memcpy (htab->splt->contents + htab->tlsdesc_plt, + 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 + - htab->tlsdesc_plt + - 6), + htab->splt->contents + htab->tlsdesc_plt + 2); + /* Add offset for jmp *GOT+TDG(%rip), where TGD stands for + htab->tlsdesc_got. The 12 is the offset to the end of + the instruction. */ + bfd_put_32 (output_bfd, + (htab->sgot->output_section->vma + + htab->sgot->output_offset + + htab->tlsdesc_got + - htab->splt->output_section->vma + - htab->splt->output_offset + - htab->tlsdesc_plt + - 12), + htab->splt->contents + htab->tlsdesc_plt + 8); + } + } + } + + if (htab->sgotplt) + { + /* Fill in the first three entries in the global offset table. */ + if (htab->sgotplt->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; + } + + if (htab->sgot && htab->sgot->size > 0) + elf_section_data (htab->sgot->output_section)->this_hdr.sh_entsize + = GOT_ENTRY_SIZE; + + return TRUE; +} + +/* Return address for Ith PLT stub in section PLT, for relocation REL + or (bfd_vma) -1 if it should not be included. */ + +static bfd_vma +elf64_x86_64_plt_sym_val (bfd_vma i, const asection *plt, + const arelent *rel ATTRIBUTE_UNUSED) +{ + return plt->vma + (i + 1) * PLT_ENTRY_SIZE; +} + +/* Handle an x86-64 specific section when reading an object file. This + is called when elfcode.h finds a section with an unknown type. */ + +static bfd_boolean +elf64_x86_64_section_from_shdr (bfd *abfd, + Elf_Internal_Shdr *hdr, + const char *name, + int shindex) +{ + if (hdr->sh_type != SHT_X86_64_UNWIND) + return FALSE; + + if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) + return FALSE; + + return TRUE; +} + +/* Hook called by the linker routine which adds symbols from an object + file. We use it to put SHN_X86_64_LCOMMON items in .lbss, instead + of .bss. */ + +static bfd_boolean +elf64_x86_64_add_symbol_hook (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + Elf_Internal_Sym *sym, + const char **namep ATTRIBUTE_UNUSED, + flagword *flagsp ATTRIBUTE_UNUSED, + asection **secp, bfd_vma *valp) +{ + asection *lcomm; + + switch (sym->st_shndx) + { + case SHN_X86_64_LCOMMON: + lcomm = bfd_get_section_by_name (abfd, "LARGE_COMMON"); + if (lcomm == NULL) + { + lcomm = bfd_make_section_with_flags (abfd, + "LARGE_COMMON", + (SEC_ALLOC + | SEC_IS_COMMON + | SEC_LINKER_CREATED)); + if (lcomm == NULL) + return FALSE; + elf_section_flags (lcomm) |= SHF_X86_64_LARGE; + } + *secp = lcomm; + *valp = sym->st_size; + break; + } + return TRUE; +} + + +/* Given a BFD section, try to locate the corresponding ELF section + index. */ + +static bfd_boolean +elf64_x86_64_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec, int *index) +{ + if (sec == &_bfd_elf_large_com_section) + { + *index = SHN_X86_64_LCOMMON; + return TRUE; + } + return FALSE; +} + +/* Process a symbol. */ + +static void +elf64_x86_64_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, + asymbol *asym) +{ + elf_symbol_type *elfsym = (elf_symbol_type *) asym; + + switch (elfsym->internal_elf_sym.st_shndx) + { + case SHN_X86_64_LCOMMON: + asym->section = &_bfd_elf_large_com_section; + asym->value = elfsym->internal_elf_sym.st_size; + /* Common symbol doesn't set BSF_GLOBAL. */ + asym->flags &= ~BSF_GLOBAL; + break; + } +} + +static bfd_boolean +elf64_x86_64_common_definition (Elf_Internal_Sym *sym) +{ + return (sym->st_shndx == SHN_COMMON + || sym->st_shndx == SHN_X86_64_LCOMMON); +} + +static unsigned int +elf64_x86_64_common_section_index (asection *sec) +{ + if ((elf_section_flags (sec) & SHF_X86_64_LARGE) == 0) + return SHN_COMMON; + else + return SHN_X86_64_LCOMMON; +} + +static asection * +elf64_x86_64_common_section (asection *sec) +{ + if ((elf_section_flags (sec) & SHF_X86_64_LARGE) == 0) + return bfd_com_section_ptr; + else + return &_bfd_elf_large_com_section; +} + +static bfd_boolean +elf64_x86_64_merge_symbol (struct bfd_link_info *info ATTRIBUTE_UNUSED, + struct elf_link_hash_entry **sym_hash ATTRIBUTE_UNUSED, + struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym, + asection **psec, + bfd_vma *pvalue ATTRIBUTE_UNUSED, + unsigned int *pold_alignment ATTRIBUTE_UNUSED, + bfd_boolean *skip ATTRIBUTE_UNUSED, + bfd_boolean *override ATTRIBUTE_UNUSED, + bfd_boolean *type_change_ok ATTRIBUTE_UNUSED, + bfd_boolean *size_change_ok ATTRIBUTE_UNUSED, + bfd_boolean *newdef ATTRIBUTE_UNUSED, + bfd_boolean *newdyn, + bfd_boolean *newdyncommon ATTRIBUTE_UNUSED, + bfd_boolean *newweak ATTRIBUTE_UNUSED, + bfd *abfd ATTRIBUTE_UNUSED, + asection **sec, + bfd_boolean *olddef ATTRIBUTE_UNUSED, + bfd_boolean *olddyn, + bfd_boolean *olddyncommon ATTRIBUTE_UNUSED, + bfd_boolean *oldweak ATTRIBUTE_UNUSED, + bfd *oldbfd, + asection **oldsec) +{ + /* A normal common symbol and a large common symbol result in a + normal common symbol. We turn the large common symbol into a + normal one. */ + if (!*olddyn + && h->root.type == bfd_link_hash_common + && !*newdyn + && bfd_is_com_section (*sec) + && *oldsec != *sec) + { + if (sym->st_shndx == SHN_COMMON + && (elf_section_flags (*oldsec) & SHF_X86_64_LARGE) != 0) + { + h->root.u.c.p->section + = bfd_make_section_old_way (oldbfd, "COMMON"); + h->root.u.c.p->section->flags = SEC_ALLOC; + } + else if (sym->st_shndx == SHN_X86_64_LCOMMON + && (elf_section_flags (*oldsec) & SHF_X86_64_LARGE) == 0) + *psec = *sec = bfd_com_section_ptr; + } + + return TRUE; +} + +static int +elf64_x86_64_additional_program_headers (bfd *abfd) +{ + asection *s; + int count = 0; + + /* Check to see if we need a large readonly segment. */ + s = bfd_get_section_by_name (abfd, ".lrodata"); + if (s && (s->flags & SEC_LOAD)) + count++; + + /* Check to see if we need a large data segment. Since .lbss sections + is placed right after the .bss section, there should be no need for + a large data segment just because of .lbss. */ + s = bfd_get_section_by_name (abfd, ".ldata"); + if (s && (s->flags & SEC_LOAD)) + count++; + + return count; +} + +static const struct bfd_elf_special_section + elf64_x86_64_special_sections[]= +{ + { ".gnu.linkonce.lb", 16, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_X86_64_LARGE}, + { ".gnu.linkonce.lr", 16, -2, SHT_PROGBITS, SHF_ALLOC + SHF_X86_64_LARGE}, + { ".gnu.linkonce.lt", 16, -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR + SHF_X86_64_LARGE}, + { ".lbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_X86_64_LARGE}, + { ".ldata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_X86_64_LARGE}, + { ".lrodata", 8, -2, SHT_PROGBITS, SHF_ALLOC + SHF_X86_64_LARGE}, + { NULL, 0, 0, 0, 0 } +}; + +#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_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_always_size_sections elf64_x86_64_always_size_sections +#define elf_backend_plt_sym_val elf64_x86_64_plt_sym_val +#define elf_backend_object_p elf64_x86_64_elf_object_p +#define bfd_elf64_mkobject elf64_x86_64_mkobject + +#define elf_backend_section_from_shdr \ + elf64_x86_64_section_from_shdr + +#define elf_backend_section_from_bfd_section \ + elf64_x86_64_elf_section_from_bfd_section +#define elf_backend_add_symbol_hook \ + elf64_x86_64_add_symbol_hook +#define elf_backend_symbol_processing \ + elf64_x86_64_symbol_processing +#define elf_backend_common_section_index \ + elf64_x86_64_common_section_index +#define elf_backend_common_section \ + elf64_x86_64_common_section +#define elf_backend_common_definition \ + elf64_x86_64_common_definition +#define elf_backend_merge_symbol \ + elf64_x86_64_merge_symbol +#define elf_backend_special_sections \ + elf64_x86_64_special_sections +#define elf_backend_additional_program_headers \ + elf64_x86_64_additional_program_headers + +#include "elf64-target.h" diff --git a/contrib/binutils-2.17/bfd/elf64.c b/contrib/binutils-2.17/bfd/elf64.c new file mode 100644 index 0000000000..5058c0c198 --- /dev/null +++ b/contrib/binutils-2.17/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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define ARCH_SIZE 64 + +#include "elfcode.h" diff --git a/contrib/binutils-2.17/bfd/elfcode.h b/contrib/binutils-2.17/bfd/elfcode.h new file mode 100644 index 0000000000..1f8ec2b2b2 --- /dev/null +++ b/contrib/binutils-2.17/bfd/elfcode.h @@ -0,0 +1,1834 @@ +/* ELF executable support for BFD. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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_canonicalize_symtab NAME(bfd_elf,canonicalize_symtab) +#define elf_canonicalize_dynamic_symtab \ + NAME(bfd_elf,canonicalize_dynamic_symtab) +#define elf_get_synthetic_symtab \ + NAME(bfd_elf,get_synthetic_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_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) + +#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 + +#ifdef DEBUG +static void elf_debug_section (int, Elf_Internal_Shdr *); +static void elf_debug_file (Elf_Internal_Ehdr *); +static char *elf_symbol_flags (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 (bfd *abfd, + const void *psrc, + const void *pshn, + Elf_Internal_Sym *dst) +{ + const Elf_External_Sym *src = psrc; + const Elf_External_Sym_Shndx *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 (bfd *abfd, + const Elf_Internal_Sym *src, + void *cdst, + void *shndx) +{ + unsigned int tmp; + Elf_External_Sym *dst = 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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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); +} + +void +elf_swap_dyn_in (bfd *abfd, + const void *p, + Elf_Internal_Dyn *dst) +{ + const Elf_External_Dyn *src = 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); +} + +void +elf_swap_dyn_out (bfd *abfd, + const Elf_Internal_Dyn *src, + void *p) +{ + Elf_External_Dyn *dst = 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 (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)); +} + +/* Determines if a given section index is valid. */ + +static inline bfd_boolean +valid_section_index_p (unsigned index, unsigned num_sections) +{ + /* Note: We allow SHN_UNDEF as a valid section index. */ + if (index < SHN_LORESERVE || index > SHN_HIRESERVE) + return index < num_sections; + + /* We disallow the use of reserved indcies, except for those + with OS or Application specific meaning. The test make use + of the knowledge that: + SHN_LORESERVE == SHN_LOPROC + and + SHN_HIPROC == SHN_LOOS - 1 */ + /* XXX - Should we allow SHN_XINDEX as a valid index here ? */ + return (index >= SHN_LOPROC && index <= SHN_HIOS); +} + +/* 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 (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; + const 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 (&x_ehdr, 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; + } + + if (!bfd_preserve_save (abfd, &preserve)) + goto got_no_match; + + /* Allocate an instance of the elf_obj_tdata structure and hook it up to + the tdata pointer in the bfd. */ + + if (! (*abfd->xvec->_bfd_set_format[bfd_object]) (abfd)) + goto got_no_match; + preserve.marker = elf_tdata (abfd); + + /* 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 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++) + { + const struct elf_backend_data *back; + + if ((*target_ptr)->flavour != bfd_target_elf_flavour) + continue; + back = (const 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; + } + + if (i_ehdrp->e_shoff != 0) + { + bfd_signed_vma where = i_ehdrp->e_shoff; + + if (where != (file_ptr) where) + goto got_wrong_format_error; + + /* Seek to the section header table in the file. */ + if (bfd_seek (abfd, (file_ptr) where, SEEK_SET) != 0) + goto got_no_match; + + /* Read the first section header at index 0, and convert to internal + form. */ + if (bfd_bread (&x_shdr, 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; + if (i_ehdrp->e_shnum != i_shdr.sh_size + || i_ehdrp->e_shnum == 0) + goto got_wrong_format_error; + } + + /* And similarly for the string table index. */ + if (i_ehdrp->e_shstrndx == SHN_XINDEX) + { + i_ehdrp->e_shstrndx = i_shdr.sh_link; + if (i_ehdrp->e_shstrndx != i_shdr.sh_link) + goto got_wrong_format_error; + } + + /* Sanity check that we can read all of the section headers. + It ought to be good enough to just read the last one. */ + if (i_ehdrp->e_shnum != 1) + { + /* Check that we don't have a totally silly number of sections. */ + if (i_ehdrp->e_shnum > (unsigned int) -1 / sizeof (x_shdr) + || i_ehdrp->e_shnum > (unsigned int) -1 / sizeof (i_shdr)) + goto got_wrong_format_error; + + where += (i_ehdrp->e_shnum - 1) * sizeof (x_shdr); + if (where != (file_ptr) where) + goto got_wrong_format_error; + if ((bfd_size_type) where <= i_ehdrp->e_shoff) + goto got_wrong_format_error; + + if (bfd_seek (abfd, (file_ptr) where, SEEK_SET) != 0) + goto got_no_match; + if (bfd_bread (&x_shdr, sizeof x_shdr, abfd) != sizeof (x_shdr)) + goto got_no_match; + + /* Back to where we were. */ + where = i_ehdrp->e_shoff + sizeof (x_shdr); + if (bfd_seek (abfd, (file_ptr) where, SEEK_SET) != 0) + goto got_no_match; + } + } + + /* 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 = 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) = 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 (&x_shdr, sizeof x_shdr, abfd) != sizeof (x_shdr)) + goto got_no_match; + elf_swap_shdr_in (abfd, &x_shdr, i_shdrp + shindex); + + /* Sanity check sh_link and sh_info. */ + if (! valid_section_index_p (i_shdrp[shindex].sh_link, num_sec)) + goto got_wrong_format_error; + + if (((i_shdrp[shindex].sh_flags & SHF_INFO_LINK) + || i_shdrp[shindex].sh_type == SHT_RELA + || i_shdrp[shindex].sh_type == SHT_REL) + && ! valid_section_index_p (i_shdrp[shindex].sh_info, num_sec)) + goto got_wrong_format_error; + + /* 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->minpagesize) + != 0)) + abfd->flags &= ~D_PAGED; + } + } + + /* A further sanity check. */ + if (i_ehdrp->e_shnum != 0) + { + if (! valid_section_index_p (i_ehdrp->e_shstrndx, elf_numsections (abfd))) + { + /* PR 2257: + We used to just goto got_wrong_format_error here + but there are binaries in existance for which this test + will prevent the binutils from working with them at all. + So we are kind, and reset the string index value to 0 + so that at least some processing can be done. */ + i_ehdrp->e_shstrndx = SHN_UNDEF; + _bfd_error_handler (_("warning: %s has a corrupt string table index - ignoring"), abfd->filename); + } + } + else if (i_ehdrp->e_shstrndx != SHN_UNDEF) + goto got_wrong_format_error; + + /* 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 = 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 (&x_phdr, sizeof x_phdr, abfd) != sizeof x_phdr) + goto got_no_match; + elf_swap_phdr_in (abfd, &x_phdr, i_phdr); + } + } + + if (i_ehdrp->e_shstrndx != 0 && i_ehdrp->e_shoff != 0) + { + unsigned int num_sec; + + /* 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; + } + + /* Set up ELF sections for SHF_GROUP and SHF_LINK_ORDER. */ + if (! _bfd_elf_setup_sections (abfd)) + goto got_wrong_format_error; + } + + /* 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; + } + + /* Remember the entry point specified in the ELF file header. */ + bfd_set_start_address (abfd, i_ehdrp->e_entry); + + /* 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 (bfd *abfd, asection *sec, void *data) +{ + bfd_boolean *failedp = data; + Elf_Internal_Shdr *rela_hdr; + bfd_vma addr_offset; + void (*swap_out) (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; + + /* If we have opened an existing file for update, reloc_count may be + set even though we are not linking. In that case we have nothing + to do. */ + if (sec->orelocation == NULL) + return; + + rela_hdr = &elf_section_data (sec)->rel_hdr; + + rela_hdr->sh_size = rela_hdr->sh_entsize * sec->reloc_count; + rela_hdr->contents = 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 (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, 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 (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 (&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 = 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 (x_shdrp, amt, abfd) != amt) + return FALSE; + + /* need to dump the string table too... */ + + return TRUE; +} + +long +elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, 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; + const 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, FALSE)) + 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 = 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 = bfd_malloc (verhdr->sh_size); + if (xverbuf == NULL && verhdr->sh_size != 0) + goto error_return; + + if (bfd_bread (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_sym_name (abfd, hdr, isym, NULL); + + 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 = bfd_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 relocatable 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; + case STT_TLS: + sym->symbol.flags |= BSF_THREAD_LOCAL; + 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 (bfd *abfd, + asection *asect, + Elf_Internal_Shdr *rel_hdr, + bfd_size_type reloc_count, + arelent *relents, + asymbol **symbols, + bfd_boolean dynamic) +{ + const struct elf_backend_data * const ebd = get_elf_backend_data (abfd); + void *allocated = NULL; + bfd_byte *native_relocs; + arelent *relent; + unsigned int i; + int entsize; + unsigned int symcount; + + allocated = 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 = 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; + + ps = symbols + ELF_R_SYM (rela.r_info) - 1; + + relent->sym_ptr_ptr = ps; + } + + 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 (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->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 = 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 (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 (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 (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 + +/* Create a new BFD as if by bfd_openr. Rather than opening a file, + reconstruct an ELF file by reading the segments out of remote memory + based on the ELF file header at EHDR_VMA and the ELF program headers it + points to. If not null, *LOADBASEP is filled in with the difference + between the VMAs from which the segments were read, and the VMAs the + file headers (and hence BFD's idea of each section's VMA) put them at. + + The function TARGET_READ_MEMORY is called to copy LEN bytes from the + remote memory at target address VMA into the local buffer at MYADDR; it + should return zero on success or an `errno' code on failure. TEMPL must + be a BFD for a target with the word size and byte order found in the + remote memory. */ + +bfd * +NAME(_bfd_elf,bfd_from_remote_memory) + (bfd *templ, + bfd_vma ehdr_vma, + bfd_vma *loadbasep, + int (*target_read_memory) (bfd_vma, bfd_byte *, int)) +{ + Elf_External_Ehdr x_ehdr; /* Elf file header, external form */ + Elf_Internal_Ehdr i_ehdr; /* Elf file header, internal form */ + Elf_External_Phdr *x_phdrs; + Elf_Internal_Phdr *i_phdrs, *last_phdr; + bfd *nbfd; + struct bfd_in_memory *bim; + int contents_size; + bfd_byte *contents; + int err; + unsigned int i; + bfd_vma loadbase; + + /* Read in the ELF header in external format. */ + err = target_read_memory (ehdr_vma, (bfd_byte *) &x_ehdr, sizeof x_ehdr); + if (err) + { + bfd_set_error (bfd_error_system_call); + errno = err; + return NULL; + } + + /* 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. */ + + if (! elf_file_p (&x_ehdr) + || x_ehdr.e_ident[EI_VERSION] != EV_CURRENT + || x_ehdr.e_ident[EI_CLASS] != ELFCLASS) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* 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 (templ)) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + break; + case ELFDATA2LSB: /* Little-endian */ + if (! bfd_header_little_endian (templ)) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + break; + case ELFDATANONE: /* No data encoding specified */ + default: /* Unknown data encoding specified */ + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + elf_swap_ehdr_in (templ, &x_ehdr, &i_ehdr); + + /* The file header tells where to find the program headers. + These are what we use to actually choose what to read. */ + + if (i_ehdr.e_phentsize != sizeof (Elf_External_Phdr) || i_ehdr.e_phnum == 0) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + x_phdrs = bfd_malloc (i_ehdr.e_phnum * (sizeof *x_phdrs + sizeof *i_phdrs)); + if (x_phdrs == NULL) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + err = target_read_memory (ehdr_vma + i_ehdr.e_phoff, (bfd_byte *) x_phdrs, + i_ehdr.e_phnum * sizeof x_phdrs[0]); + if (err) + { + free (x_phdrs); + bfd_set_error (bfd_error_system_call); + errno = err; + return NULL; + } + i_phdrs = (Elf_Internal_Phdr *) &x_phdrs[i_ehdr.e_phnum]; + + contents_size = 0; + last_phdr = NULL; + loadbase = ehdr_vma; + for (i = 0; i < i_ehdr.e_phnum; ++i) + { + elf_swap_phdr_in (templ, &x_phdrs[i], &i_phdrs[i]); + /* IA-64 vDSO may have two mappings for one segment, where one mapping + is executable only, and one is read only. We must not use the + executable one. */ + if (i_phdrs[i].p_type == PT_LOAD && (i_phdrs[i].p_flags & PF_R)) + { + bfd_vma segment_end; + segment_end = (i_phdrs[i].p_offset + i_phdrs[i].p_filesz + + i_phdrs[i].p_align - 1) & -i_phdrs[i].p_align; + if (segment_end > (bfd_vma) contents_size) + contents_size = segment_end; + + if ((i_phdrs[i].p_offset & -i_phdrs[i].p_align) == 0) + loadbase = ehdr_vma - (i_phdrs[i].p_vaddr & -i_phdrs[i].p_align); + + last_phdr = &i_phdrs[i]; + } + } + if (last_phdr == NULL) + { + /* There were no PT_LOAD segments, so we don't have anything to read. */ + free (x_phdrs); + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* Trim the last segment so we don't bother with zeros in the last page + that are off the end of the file. However, if the extra bit in that + page includes the section headers, keep them. */ + if ((bfd_vma) contents_size > last_phdr->p_offset + last_phdr->p_filesz + && (bfd_vma) contents_size >= (i_ehdr.e_shoff + + i_ehdr.e_shnum * i_ehdr.e_shentsize)) + { + contents_size = last_phdr->p_offset + last_phdr->p_filesz; + if ((bfd_vma) contents_size < (i_ehdr.e_shoff + + i_ehdr.e_shnum * i_ehdr.e_shentsize)) + contents_size = i_ehdr.e_shoff + i_ehdr.e_shnum * i_ehdr.e_shentsize; + } + else + contents_size = last_phdr->p_offset + last_phdr->p_filesz; + + /* Now we know the size of the whole image we want read in. */ + contents = bfd_zmalloc (contents_size); + if (contents == NULL) + { + free (x_phdrs); + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + for (i = 0; i < i_ehdr.e_phnum; ++i) + /* IA-64 vDSO may have two mappings for one segment, where one mapping + is executable only, and one is read only. We must not use the + executable one. */ + if (i_phdrs[i].p_type == PT_LOAD && (i_phdrs[i].p_flags & PF_R)) + { + bfd_vma start = i_phdrs[i].p_offset & -i_phdrs[i].p_align; + bfd_vma end = (i_phdrs[i].p_offset + i_phdrs[i].p_filesz + + i_phdrs[i].p_align - 1) & -i_phdrs[i].p_align; + if (end > (bfd_vma) contents_size) + end = contents_size; + err = target_read_memory ((loadbase + i_phdrs[i].p_vaddr) + & -i_phdrs[i].p_align, + contents + start, end - start); + if (err) + { + free (x_phdrs); + free (contents); + bfd_set_error (bfd_error_system_call); + errno = err; + return NULL; + } + } + free (x_phdrs); + + /* If the segments visible in memory didn't include the section headers, + then clear them from the file header. */ + if ((bfd_vma) contents_size < (i_ehdr.e_shoff + + i_ehdr.e_shnum * i_ehdr.e_shentsize)) + { + memset (&x_ehdr.e_shoff, 0, sizeof x_ehdr.e_shoff); + memset (&x_ehdr.e_shnum, 0, sizeof x_ehdr.e_shnum); + memset (&x_ehdr.e_shstrndx, 0, sizeof x_ehdr.e_shstrndx); + } + + /* This will normally have been in the first PT_LOAD segment. But it + conceivably could be missing, and we might have just changed it. */ + memcpy (contents, &x_ehdr, sizeof x_ehdr); + + /* Now we have a memory image of the ELF file contents. Make a BFD. */ + bim = bfd_malloc (sizeof (struct bfd_in_memory)); + if (bim == NULL) + { + free (contents); + bfd_set_error (bfd_error_no_memory); + return NULL; + } + nbfd = _bfd_new_bfd (); + if (nbfd == NULL) + { + free (bim); + free (contents); + bfd_set_error (bfd_error_no_memory); + return NULL; + } + nbfd->filename = ""; + nbfd->xvec = templ->xvec; + bim->size = contents_size; + bim->buffer = contents; + nbfd->iostream = bim; + nbfd->flags = BFD_IN_MEMORY; + nbfd->direction = read_direction; + nbfd->mtime = time (NULL); + nbfd->mtime_set = TRUE; + + if (loadbasep) + *loadbasep = loadbase; + return nbfd; +} + +#include "elfcore.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, LOG_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.17/bfd/elfcore.h b/contrib/binutils-2.17/bfd/elfcore.h new file mode 100644 index 0000000000..b1cf42d79f --- /dev/null +++ b/contrib/binutils-2.17/bfd/elfcore.h @@ -0,0 +1,251 @@ +/* ELF core file support for BFD. + Copyright 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +char* +elf_core_file_failing_command (bfd *abfd) +{ + return elf_tdata (abfd)->core_command; +} + +int +elf_core_file_failing_signal (bfd *abfd) +{ + return elf_tdata (abfd)->core_signal; +} + +bfd_boolean +elf_core_file_matches_executable_p (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 (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; + const 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 (&x_ehdr, 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; + } + + if (!bfd_preserve_save (abfd, &preserve)) + goto fail; + + /* Give abfd an elf_obj_tdata. */ + if (! (*abfd->xvec->_bfd_set_format[bfd_core]) (abfd)) + goto fail; + preserve.marker = elf_tdata (abfd); + + /* 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++) + { + const struct elf_backend_data *back; + + if ((*target_ptr)->flavour != bfd_target_elf_flavour) + continue; + back = (const 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 = 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 (&x_phdr, 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. */ + && ebd->elf_machine_code != EM_NONE) + goto fail; + + /* Let the backend double check the format and override global + information. We do this before processing the program headers + to allow the correct machine (as opposed to just the default + machine) to be set, making it possible for grok_prstatus and + grok_psinfo to rely on the mach setting. */ + if (ebd->elf_backend_object_p != NULL + && ! ebd->elf_backend_object_p (abfd)) + goto wrong; + + /* 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; + + 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.17/bfd/elflink.c b/contrib/binutils-2.17/bfd/elflink.c new file mode 100644 index 0000000000..99f044b783 --- /dev/null +++ b/contrib/binutils-2.17/bfd/elflink.c @@ -0,0 +1,9943 @@ +/* ELF linking support for BFD. + Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, + 2005, 2006 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#define ARCH_SIZE 0 +#include "elf-bfd.h" +#include "safe-ctype.h" +#include "libiberty.h" +#include "objalloc.h" + +/* Define a symbol in a dynamic linkage section. */ + +struct elf_link_hash_entry * +_bfd_elf_define_linkage_sym (bfd *abfd, + struct bfd_link_info *info, + asection *sec, + const char *name) +{ + struct elf_link_hash_entry *h; + struct bfd_link_hash_entry *bh; + const struct elf_backend_data *bed; + + h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, FALSE); + if (h != NULL) + { + /* Zap symbol defined in an as-needed lib that wasn't linked. + This is a symptom of a larger problem: Absolute symbols + defined in shared libraries can't be overridden, because we + lose the link to the bfd which is via the symbol section. */ + h->root.type = bfd_link_hash_new; + } + + bh = &h->root; + if (!_bfd_generic_link_add_one_symbol (info, abfd, name, BSF_GLOBAL, + sec, 0, NULL, FALSE, + get_elf_backend_data (abfd)->collect, + &bh)) + return NULL; + h = (struct elf_link_hash_entry *) bh; + h->def_regular = 1; + h->type = STT_OBJECT; + h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; + + bed = get_elf_backend_data (abfd); + (*bed->elf_backend_hide_symbol) (info, h, TRUE); + return h; +} + +bfd_boolean +_bfd_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) +{ + flagword flags; + asection *s; + struct elf_link_hash_entry *h; + const 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 = bed->dynamic_sec_flags; + + s = bfd_make_section_with_flags (abfd, ".got", flags); + if (s == NULL + || !bfd_set_section_alignment (abfd, s, ptralign)) + return FALSE; + + if (bed->want_got_plt) + { + s = bfd_make_section_with_flags (abfd, ".got.plt", flags); + if (s == NULL + || !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. */ + h = _bfd_elf_define_linkage_sym (abfd, info, s, "_GLOBAL_OFFSET_TABLE_"); + elf_hash_table (info)->hgot = h; + if (h == NULL) + return FALSE; + } + + /* The first bit of the global offset table is the header. */ + s->size += bed->got_header_size; + + return TRUE; +} + +/* Create a strtab to hold the dynamic symbol names. */ +static bfd_boolean +_bfd_elf_link_create_dynstrtab (bfd *abfd, struct bfd_link_info *info) +{ + struct elf_link_hash_table *hash_table; + + hash_table = elf_hash_table (info); + if (hash_table->dynobj == NULL) + hash_table->dynobj = abfd; + + if (hash_table->dynstr == NULL) + { + hash_table->dynstr = _bfd_elf_strtab_init (); + if (hash_table->dynstr == NULL) + return FALSE; + } + return TRUE; +} + +/* 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 +_bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) +{ + flagword flags; + register asection *s; + const struct elf_backend_data *bed; + + if (! is_elf_hash_table (info->hash)) + return FALSE; + + if (elf_hash_table (info)->dynamic_sections_created) + return TRUE; + + if (!_bfd_elf_link_create_dynstrtab (abfd, info)) + return FALSE; + + abfd = elf_hash_table (info)->dynobj; + bed = get_elf_backend_data (abfd); + + flags = bed->dynamic_sec_flags; + + /* A dynamically linked executable has a .interp section, but a + shared library does not. */ + if (info->executable) + { + s = bfd_make_section_with_flags (abfd, ".interp", + flags | SEC_READONLY); + if (s == NULL) + return FALSE; + } + + if (! info->traditional_format) + { + s = bfd_make_section_with_flags (abfd, ".eh_frame_hdr", + flags | SEC_READONLY); + if (s == NULL + || ! 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_with_flags (abfd, ".gnu.version_d", + flags | SEC_READONLY); + if (s == NULL + || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) + return FALSE; + + s = bfd_make_section_with_flags (abfd, ".gnu.version", + flags | SEC_READONLY); + if (s == NULL + || ! bfd_set_section_alignment (abfd, s, 1)) + return FALSE; + + s = bfd_make_section_with_flags (abfd, ".gnu.version_r", + flags | SEC_READONLY); + if (s == NULL + || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) + return FALSE; + + s = bfd_make_section_with_flags (abfd, ".dynsym", + flags | SEC_READONLY); + if (s == NULL + || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) + return FALSE; + + s = bfd_make_section_with_flags (abfd, ".dynstr", + flags | SEC_READONLY); + if (s == NULL) + return FALSE; + + s = bfd_make_section_with_flags (abfd, ".dynamic", flags); + if (s == NULL + || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) + return FALSE; + + /* The special symbol _DYNAMIC is always set to the start of the + .dynamic section. 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. */ + if (!_bfd_elf_define_linkage_sym (abfd, info, s, "_DYNAMIC")) + return FALSE; + + s = bfd_make_section_with_flags (abfd, ".hash", + flags | SEC_READONLY); + if (s == NULL + || ! bfd_set_section_alignment (abfd, s, bed->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; +} + +/* Create dynamic sections when linking against a dynamic object. */ + +bfd_boolean +_bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) +{ + flagword flags, pltflags; + struct elf_link_hash_entry *h; + asection *s; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + + /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and + .rel[a].bss sections. */ + flags = bed->dynamic_sec_flags; + + pltflags = flags; + if (bed->plt_not_loaded) + /* We do not clear SEC_ALLOC here because we still want the OS to + allocate space for the section; it's just that there's nothing + to read in from the object file. */ + pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS); + else + pltflags |= SEC_ALLOC | SEC_CODE | SEC_LOAD; + if (bed->plt_readonly) + pltflags |= SEC_READONLY; + + s = bfd_make_section_with_flags (abfd, ".plt", pltflags); + if (s == NULL + || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) + return FALSE; + + /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the + .plt section. */ + if (bed->want_plt_sym) + { + h = _bfd_elf_define_linkage_sym (abfd, info, s, + "_PROCEDURE_LINKAGE_TABLE_"); + elf_hash_table (info)->hplt = h; + if (h == NULL) + return FALSE; + } + + s = bfd_make_section_with_flags (abfd, + (bed->default_use_rela_p + ? ".rela.plt" : ".rel.plt"), + flags | SEC_READONLY); + if (s == NULL + || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) + 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_with_flags (abfd, ".dynbss", + (SEC_ALLOC + | SEC_LINKER_CREATED)); + if (s == NULL) + 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_with_flags (abfd, + (bed->default_use_rela_p + ? ".rela.bss" : ".rel.bss"), + flags | SEC_READONLY); + if (s == NULL + || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) + 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 (struct bfd_link_info *info, + struct elf_link_hash_entry *h) +{ + if (h->dynindx == -1) + { + struct elf_strtab_hash *dynstr; + char *p; + const char *name; + 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->forced_local = 1; + if (!elf_hash_table (info)->is_relocatable_executable) + 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) + /* We know that the p points into writable memory. In fact, + there are only a few symbols that have read-only names, being + those like _GLOBAL_OFFSET_TABLE_ that are created specially + by the backends. Most symbols will have names pointing into + an ELF string table read from a file, or to objalloc memory. */ + *p = 0; + + indx = _bfd_elf_strtab_add (dynstr, name, p != NULL); + + if (p != NULL) + *p = ELF_VER_CHR; + + if (indx == (bfd_size_type) -1) + return FALSE; + h->dynstr_index = indx; + } + + return TRUE; +} + +/* 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 +bfd_elf_record_link_assignment (bfd *output_bfd, + struct bfd_link_info *info, + const char *name, + bfd_boolean provide, + bfd_boolean hidden) +{ + struct elf_link_hash_entry *h; + struct elf_link_hash_table *htab; + + if (!is_elf_hash_table (info->hash)) + return TRUE; + + htab = elf_hash_table (info); + h = elf_link_hash_lookup (htab, name, !provide, TRUE, FALSE); + if (h == NULL) + return provide; + + /* Since we're defining the symbol, don't let it seem to have not + been defined. record_dynamic_symbol and size_dynamic_sections + may depend on this. */ + if (h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined) + { + h->root.type = bfd_link_hash_new; + if (h->root.u.undef.next != NULL || htab->root.undefs_tail == &h->root) + bfd_link_repair_undef_list (&htab->root); + } + + if (h->root.type == bfd_link_hash_new) + h->non_elf = 0; + + /* 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->def_dynamic + && !h->def_regular) + 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->def_dynamic + && !h->def_regular) + h->verinfo.verdef = NULL; + + h->def_regular = 1; + + if (provide && hidden) + { + const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); + + h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; + (*bed->elf_backend_hide_symbol) (info, h, TRUE); + } + + /* STV_HIDDEN and STV_INTERNAL symbols must be STB_LOCAL in shared objects + and executables. */ + if (!info->relocatable + && h->dynindx != -1 + && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN + || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)) + h->forced_local = 1; + + if ((h->def_dynamic + || h->ref_dynamic + || info->shared + || (info->executable && elf_hash_table (info)->is_relocatable_executable)) + && 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->u.weakdef != NULL + && h->u.weakdef->dynindx == -1) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h->u.weakdef)) + return FALSE; + } + } + + 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 +bfd_elf_link_record_local_dynamic_symbol (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->hash)) + 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 = 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, + 1, 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 (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 (struct elf_link_hash_entry *h, + void *data) +{ + size_t *count = data; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + if (h->forced_local) + return TRUE; + + if (h->dynindx != -1) + h->dynindx = ++(*count); + + return TRUE; +} + + +/* Like elf_link_renumber_hash_table_dynsyms, but just number symbols with + STB_LOCAL binding. */ + +static bfd_boolean +elf_link_renumber_local_hash_table_dynsyms (struct elf_link_hash_entry *h, + void *data) +{ + size_t *count = data; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + if (!h->forced_local) + return TRUE; + + if (h->dynindx != -1) + h->dynindx = ++(*count); + + return TRUE; +} + +/* Return true if the dynamic symbol for a given section should be + omitted when creating a shared library. */ +bfd_boolean +_bfd_elf_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info, + asection *p) +{ + switch (elf_section_data (p)->this_hdr.sh_type) + { + case SHT_PROGBITS: + case SHT_NOBITS: + /* If sh_type is yet undecided, assume it could be + SHT_PROGBITS/SHT_NOBITS. */ + case SHT_NULL: + if (strcmp (p->name, ".got") == 0 + || strcmp (p->name, ".got.plt") == 0 + || strcmp (p->name, ".plt") == 0) + { + asection *ip; + bfd *dynobj = elf_hash_table (info)->dynobj; + + if (dynobj != NULL + && (ip = bfd_get_section_by_name (dynobj, p->name)) != NULL + && (ip->flags & SEC_LINKER_CREATED) + && ip->output_section == p) + return TRUE; + } + return FALSE; + + /* There shouldn't be section relative relocations + against any other section. */ + default: + return TRUE; + } +} + +/* Assign dynsym indices. In a shared library we generate a section + symbol for each output section, which come first. Next come symbols + which have been forced to local binding. Then all of the back-end + allocated local dynamic syms, followed by the rest of the global + symbols. */ + +static unsigned long +_bfd_elf_link_renumber_dynsyms (bfd *output_bfd, + struct bfd_link_info *info, + unsigned long *section_sym_count) +{ + unsigned long dynsymcount = 0; + + if (info->shared || elf_hash_table (info)->is_relocatable_executable) + { + const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); + asection *p; + for (p = output_bfd->sections; p ; p = p->next) + if ((p->flags & SEC_EXCLUDE) == 0 + && (p->flags & SEC_ALLOC) != 0 + && !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p)) + elf_section_data (p)->dynindx = ++dynsymcount; + } + *section_sym_count = dynsymcount; + + elf_link_hash_traverse (elf_hash_table (info), + elf_link_renumber_local_hash_table_dynsyms, + &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; + + elf_hash_table (info)->dynsymcount = dynsymcount; + return dynsymcount; +} + +/* This function is called when we want to define a new symbol. It + handles the various cases which arise when we find a definition in + a dynamic object, or when there is already a definition in a + dynamic object. The new symbol is described by NAME, SYM, PSEC, + and PVALUE. We set SYM_HASH to the hash table entry. We set + OVERRIDE if the old symbol is overriding a new definition. We set + TYPE_CHANGE_OK if it is OK for the type to change. We set + SIZE_CHANGE_OK if it is OK for the size to change. By OK to + change, we mean that we shouldn't warn if the type or size does + change. We set POLD_ALIGNMENT if an old common symbol in a dynamic + object is overridden by a regular object. */ + +bfd_boolean +_bfd_elf_merge_symbol (bfd *abfd, + struct bfd_link_info *info, + const char *name, + Elf_Internal_Sym *sym, + asection **psec, + bfd_vma *pvalue, + unsigned int *pold_alignment, + struct elf_link_hash_entry **sym_hash, + bfd_boolean *skip, + bfd_boolean *override, + bfd_boolean *type_change_ok, + bfd_boolean *size_change_ok) +{ + asection *sec, *oldsec; + 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 newweak, oldweak; + const struct elf_backend_data *bed; + + *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->non_elf = 0; + return TRUE; + } + + /* OLDBFD and OLDSEC are a BFD and an ASECTION associated with the + existing symbol. */ + + switch (h->root.type) + { + default: + oldbfd = NULL; + oldsec = NULL; + break; + + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + oldbfd = h->root.u.undef.abfd; + oldsec = NULL; + break; + + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + oldbfd = h->root.u.def.section->owner; + oldsec = h->root.u.def.section; + break; + + case bfd_link_hash_common: + oldbfd = h->root.u.c.p->section->owner; + oldsec = h->root.u.c.p->section; + break; + } + + /* 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->def_regular)) + return TRUE; + + /* NEWDYN and OLDDYN indicate whether the new or old symbol, + respectively, is from a dynamic object. */ + + newdyn = (abfd->flags & DYNAMIC) != 0; + + olddyn = FALSE; + if (oldbfd != NULL) + olddyn = (oldbfd->flags & DYNAMIC) != 0; + else if (oldsec != NULL) + { + /* This handles the special SHN_MIPS_{TEXT,DATA} section + indices used by MIPS ELF. */ + olddyn = (oldsec->symbol->flags & BSF_DYNAMIC) != 0; + } + + /* NEWDEF and OLDDEF indicate whether the new or old symbol, + respectively, appear to be a definition rather than reference. */ + + newdef = !bfd_is_und_section (sec) && !bfd_is_com_section (sec); + + olddef = (h->root.type != bfd_link_hash_undefined + && h->root.type != bfd_link_hash_undefweak + && h->root.type != bfd_link_hash_common); + + /* When we try to create a default indirect symbol from the dynamic + definition with the default version, we skip it if its type and + the type of existing regular definition mismatch. We only do it + if the existing regular definition won't be dynamic. */ + if (pold_alignment == NULL + && !info->shared + && !info->export_dynamic + && !h->ref_dynamic + && newdyn + && newdef + && !olddyn + && (olddef || h->root.type == bfd_link_hash_common) + && ELF_ST_TYPE (sym->st_info) != h->type + && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE + && h->type != STT_NOTYPE) + { + *skip = TRUE; + return TRUE; + } + + /* Check TLS symbol. We don't check undefined symbol introduced by + "ld -u". */ + if ((ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS) + && ELF_ST_TYPE (sym->st_info) != h->type + && oldbfd != NULL) + { + bfd *ntbfd, *tbfd; + bfd_boolean ntdef, tdef; + asection *ntsec, *tsec; + + if (h->type == STT_TLS) + { + ntbfd = abfd; + ntsec = sec; + ntdef = newdef; + tbfd = oldbfd; + tsec = oldsec; + tdef = olddef; + } + else + { + ntbfd = oldbfd; + ntsec = oldsec; + ntdef = olddef; + tbfd = abfd; + tsec = sec; + tdef = newdef; + } + + if (tdef && ntdef) + (*_bfd_error_handler) + (_("%s: TLS definition in %B section %A mismatches non-TLS definition in %B section %A"), + tbfd, tsec, ntbfd, ntsec, h->root.root.string); + else if (!tdef && !ntdef) + (*_bfd_error_handler) + (_("%s: TLS reference in %B mismatches non-TLS reference in %B"), + tbfd, ntbfd, h->root.root.string); + else if (tdef) + (*_bfd_error_handler) + (_("%s: TLS definition in %B section %A mismatches non-TLS reference in %B"), + tbfd, tsec, ntbfd, h->root.root.string); + else + (*_bfd_error_handler) + (_("%s: TLS reference in %B mismatches non-TLS definition in %B section %A"), + tbfd, ntbfd, ntsec, h->root.root.string); + + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + /* We need to remember 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->dynamic_def) + { + if (!bfd_is_und_section (sec)) + h->dynamic_def = 1; + 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->ref_dynamic) + { + if (bind == STB_WEAK) + h->dynamic_weak = 1; + } + else if (bind != STB_WEAK) + h->dynamic_weak = 0; + } + } + + /* If the old symbol has non-default visibility, we ignore the new + definition from a dynamic object. */ + if (newdyn + && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT + && !bfd_is_und_section (sec)) + { + *skip = TRUE; + /* Make sure this symbol is dynamic. */ + h->ref_dynamic = 1; + /* 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) != STV_DEFAULT + && h->def_dynamic) + { + /* 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; + + if ((h->root.u.undef.next || info->hash->undefs_tail == &h->root) + && bfd_is_und_section (sec)) + { + /* If the new symbol is undefined and the old symbol was + also undefined before, we need to make sure + _bfd_generic_link_add_one_symbol doesn't mess + up the linker hash table undefs list. Since the old + definition came from a dynamic object, it is still on the + undefs list. */ + h->root.type = bfd_link_hash_undefined; + h->root.u.undef.abfd = abfd; + } + else + { + h->root.type = bfd_link_hash_new; + h->root.u.undef.abfd = NULL; + } + + if (h->def_dynamic) + { + h->def_dynamic = 0; + h->ref_dynamic = 1; + h->dynamic_def = 1; + } + /* FIXME: Should we check type and size for protected symbol? */ + h->size = 0; + h->type = 0; + return TRUE; + } + + /* Differentiate strong and weak symbols. */ + newweak = bind == STB_WEAK; + oldweak = (h->root.type == bfd_link_hash_defweak + || h->root.type == bfd_link_hash_undefweak); + + /* If a new weak symbol definition comes from a regular file and the + old symbol comes from a dynamic library, we treat the new one as + strong. Similarly, an old weak symbol definition from a regular + file is treated as strong when the new symbol comes from a dynamic + library. Further, an old weak symbol from a dynamic library is + treated as strong if the new symbol is from a dynamic library. + This reflects the way glibc's ld.so works. + + Do this before setting *type_change_ok or *size_change_ok so that + we warn properly when dynamic library symbols are overridden. */ + + if (newdef && !newdyn && olddyn) + newweak = FALSE; + if (olddef && newdyn) + oldweak = FALSE; + + /* It's OK to change the type if either the existing symbol or the + new symbol is weak. A type change is also OK if the old symbol + is undefined and the new symbol is defined. */ + + if (oldweak + || newweak + || (newdef + && h->root.type == bfd_link_hash_undefined)) + *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; + + /* 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 + && !newweak + && (sec->flags & SEC_ALLOC) != 0 + && (sec->flags & SEC_LOAD) == 0 + && sym->st_size > 0 + && ELF_ST_TYPE (sym->st_info) != STT_FUNC) + newdyncommon = TRUE; + else + newdyncommon = FALSE; + + if (olddyn + && olddef + && h->root.type == bfd_link_hash_defined + && h->def_dynamic + && (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; + + /* We now know everything about the old and new symbols. We ask the + backend to check if we can merge them. */ + bed = get_elf_backend_data (abfd); + if (bed->merge_symbol + && !bed->merge_symbol (info, sym_hash, h, sym, psec, pvalue, + pold_alignment, skip, override, + type_change_ok, size_change_ok, + &newdyn, &newdef, &newdyncommon, &newweak, + abfd, &sec, + &olddyn, &olddef, &olddyncommon, &oldweak, + oldbfd, &oldsec)) + return FALSE; + + /* If 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. */ + + if (newdyn + && newdef + && (olddef + || (h->root.type == bfd_link_hash_common + && (newweak + || ELF_ST_TYPE (sym->st_info) == STT_FUNC)))) + { + *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 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 = bed->common_section (oldsec); + *size_change_ok = TRUE; + } + + /* Skip weak definitions of symbols that are already defined. */ + if (newdef && olddef && newweak) + *skip = 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. */ + + flip = NULL; + if (!newdyn + && (newdef + || (bfd_is_com_section (sec) + && (oldweak + || h->type == STT_FUNC))) + && olddyn + && olddef + && h->def_dynamic) + { + /* 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 presumed common symbol in the dynamic object is + larger, pretend that the new symbol has its size. */ + + if (h->size > *pvalue) + *pvalue = h->size; + + /* We need to remember the alignment required by the symbol + in the dynamic object. */ + BFD_ASSERT (pold_alignment); + *pold_alignment = h->root.u.def.section->alignment_power; + + 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. */ + const 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) (info, flip, h); + flip->root.u.undef.abfd = h->root.u.undef.abfd; + if (h->def_dynamic) + { + h->def_dynamic = 0; + flip->ref_dynamic = 1; + } + } + + 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. */ + +bfd_boolean +_bfd_elf_add_default_symbol (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 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; + const 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 definition. We need to check if we + need to create the indirect symbol from the default name. */ + hi = elf_link_hash_lookup (elf_hash_table (info), name, TRUE, + FALSE, FALSE); + BFD_ASSERT (hi != NULL); + if (hi == h) + return TRUE; + while (hi->root.type == bfd_link_hash_indirect + || hi->root.type == bfd_link_hash_warning) + { + hi = (struct elf_link_hash_entry *) hi->root.u.i.link; + if (hi == h) + return TRUE; + } + } + + bed = get_elf_backend_data (abfd); + collect = bed->collect; + dynamic = (abfd->flags & DYNAMIC) != 0; + + 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 (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value, + NULL, &hi, &skip, &override, + &type_change_ok, &size_change_ok)) + 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, + 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->def_dynamic) + { + h->def_dynamic = 0; + hi->ref_dynamic = 1; + if (hi->ref_regular + || hi->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; + + ht = (struct elf_link_hash_entry *) hi->root.u.i.link; + (*bed->elf_backend_copy_indirect_symbol) (info, 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->ref_dynamic) + *dynsym = TRUE; + } + else + { + if (hi->ref_regular) + *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 (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value, + NULL, &hi, &skip, &override, + &type_change_ok, &size_change_ok)) + 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 definition. */ + if (hi->root.type != bfd_link_hash_defined + && hi->root.type != bfd_link_hash_defweak) + (*_bfd_error_handler) + (_("%B: unexpected redefinition of indirect versioned symbol `%s'"), + abfd, shortname); + } + else + { + bh = &hi->root; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, shortname, BSF_INDIRECT, + bfd_ind_section_ptr, 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) + { + (*bed->elf_backend_copy_indirect_symbol) (info, 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->ref_dynamic) + *dynsym = TRUE; + } + else + { + if (hi->ref_regular) + *dynsym = TRUE; + } + } + } + } + + return TRUE; +} + +/* This routine is used to export all defined symbols into the dynamic + symbol table. It is called via elf_link_hash_traverse. */ + +bfd_boolean +_bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data) +{ + struct elf_info_failed *eif = 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->def_regular + || h->ref_regular)) + { + struct bfd_elf_version_tree *t; + struct bfd_elf_version_expr *d; + + for (t = eif->verdefs; t != NULL; t = t->next) + { + if (t->globals.list != NULL) + { + d = (*t->match) (&t->globals, NULL, h->root.root.string); + if (d != NULL) + goto doit; + } + + if (t->locals.list != NULL) + { + d = (*t->match) (&t->locals, NULL, h->root.root.string); + if (d != NULL) + 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. */ + +bfd_boolean +_bfd_elf_link_find_version_dependencies (struct elf_link_hash_entry *h, + void *data) +{ + struct elf_find_verdep_info *rinfo = 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->def_dynamic + || h->def_regular + || 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 = 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 = 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. */ + +bfd_boolean +_bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data) +{ + struct elf_assign_sym_version_info *sinfo; + struct bfd_link_info *info; + const struct elf_backend_data *bed; + struct elf_info_failed eif; + char *p; + bfd_size_type amt; + + sinfo = 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 (! _bfd_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->def_regular) + 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->hidden = 1; + 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 (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.list != NULL) + d = (*t->match) (&t->globals, NULL, alc); + + /* See if there is anything to force this symbol to + local scope. */ + if (d == NULL && t->locals.list != NULL) + { + d = (*t->match) (&t->locals, NULL, alc); + if (d != NULL + && h->dynindx != -1 + && ! info->export_dynamic) + (*bed->elf_backend_hide_symbol) (info, h, TRUE); + } + + free (alc); + break; + } + } + + /* If we are building an application, we need to create a + version node for this version. */ + if (t == NULL && info->executable) + { + 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 = bfd_zalloc (sinfo->output_bfd, amt); + if (t == NULL) + { + sinfo->failed = TRUE; + return FALSE; + } + + t->name = p; + 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) + (_("%B: undefined versioned symbol name %s"), + sinfo->output_bfd, h->root.root.string); + bfd_set_error (bfd_error_bad_value); + sinfo->failed = TRUE; + return FALSE; + } + + if (hidden) + h->hidden = 1; + } + + /* 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.list != NULL) + { + bfd_boolean matched; + + matched = FALSE; + d = NULL; + while ((d = (*t->match) (&t->globals, d, + h->root.root.string)) != NULL) + 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.list != NULL) + { + d = NULL; + while ((d = (*t->match) (&t->locals, d, + h->root.root.string)) != NULL) + { + local_ver = t; + /* If the match is "*", keep looking for a more + explicit, perhaps even global, match. + XXX: Shouldn't this be !d->wildcard instead? */ + if (d->pattern[0] != '*' || d->pattern[1] != '\0') + break; + } + + if (d != NULL) + break; + } + } + + if (local_ver != NULL) + { + h->verinfo.vertree = local_ver; + if (h->dynindx != -1 + && ! info->export_dynamic) + { + (*bed->elf_backend_hide_symbol) (info, h, TRUE); + } + } + } + + 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 (bfd *abfd, + asection *sec, + Elf_Internal_Shdr *shdr, + void *external_relocs, + Elf_Internal_Rela *internal_relocs) +{ + const struct elf_backend_data *bed; + void (*swap_in) (bfd *, const bfd_byte *, Elf_Internal_Rela *); + const bfd_byte *erela; + const bfd_byte *erelaend; + Elf_Internal_Rela *irela; + Elf_Internal_Shdr *symtab_hdr; + size_t nsyms; + + /* 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; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + nsyms = symtab_hdr->sh_size / symtab_hdr->sh_entsize; + + bed = get_elf_backend_data (abfd); + + /* Convert the external relocations to the internal format. */ + if (shdr->sh_entsize == bed->s->sizeof_rel) + swap_in = bed->s->swap_reloc_in; + else if (shdr->sh_entsize == bed->s->sizeof_rela) + swap_in = bed->s->swap_reloca_in; + else + { + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + + erela = external_relocs; + erelaend = erela + shdr->sh_size; + irela = internal_relocs; + while (erela < erelaend) + { + bfd_vma r_symndx; + + (*swap_in) (abfd, erela, irela); + r_symndx = ELF32_R_SYM (irela->r_info); + if (bed->s->arch_size == 64) + r_symndx >>= 24; + if ((size_t) r_symndx >= nsyms) + { + (*_bfd_error_handler) + (_("%B: bad reloc symbol index (0x%lx >= 0x%lx)" + " for offset 0x%lx in section `%A'"), + abfd, sec, + (unsigned long) r_symndx, (unsigned long) nsyms, irela->r_offset); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + 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 * +_bfd_elf_link_read_relocs (bfd *abfd, + asection *o, + void *external_relocs, + Elf_Internal_Rela *internal_relocs, + bfd_boolean keep_memory) +{ + Elf_Internal_Shdr *rel_hdr; + void *alloc1 = NULL; + Elf_Internal_Rela *alloc2 = NULL; + const 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 = bfd_alloc (abfd, size); + else + internal_relocs = alloc2 = 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 = bfd_malloc (size); + if (alloc1 == NULL) + goto error_return; + external_relocs = alloc1; + } + + if (!elf_link_read_relocs_from_section (abfd, o, rel_hdr, + external_relocs, + internal_relocs)) + goto error_return; + if (elf_section_data (o)->rel_hdr2 + && (!elf_link_read_relocs_from_section + (abfd, o, + 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; +} + +/* Compute the size of, and allocate space for, REL_HDR which is the + section header for a section containing relocations for O. */ + +bfd_boolean +_bfd_elf_link_size_reloc_section (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 = 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 = 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; +} + +/* Copy the relocations indicated by the INTERNAL_RELOCS (which + originated from the section given by INPUT_REL_HDR) to the + OUTPUT_BFD. */ + +bfd_boolean +_bfd_elf_link_output_relocs (bfd *output_bfd, + asection *input_section, + Elf_Internal_Shdr *input_rel_hdr, + Elf_Internal_Rela *internal_relocs, + struct elf_link_hash_entry **rel_hash + ATTRIBUTE_UNUSED) +{ + 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; + const struct elf_backend_data *bed; + void (*swap_out) (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) + (_("%B: relocation size mismatch in %B section %A"), + output_bfd, input_section->owner, input_section); + bfd_set_error (bfd_error_wrong_object_format); + return FALSE; + } + + bed = get_elf_backend_data (output_bfd); + if (input_rel_hdr->sh_entsize == bed->s->sizeof_rel) + swap_out = bed->s->swap_reloc_out; + else if (input_rel_hdr->sh_entsize == bed->s->sizeof_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; +} + +/* Make weak undefined symbols in PIE dynamic. */ + +bfd_boolean +_bfd_elf_link_hash_fixup_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *h) +{ + if (info->pie + && h->dynindx == -1 + && h->root.type == bfd_link_hash_undefweak) + return bfd_elf_link_record_dynamic_symbol (info, h); + + 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. */ + +bfd_boolean +_bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h, + struct elf_info_failed *eif) +{ + const struct elf_backend_data *bed = NULL; + + /* 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->non_elf) + { + 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->ref_regular = 1; + h->ref_regular_nonweak = 1; + } + else + { + if (h->root.u.def.section->owner != NULL + && (bfd_get_flavour (h->root.u.def.section->owner) + == bfd_target_elf_flavour)) + { + h->ref_regular = 1; + h->ref_regular_nonweak = 1; + } + else + h->def_regular = 1; + } + + if (h->dynindx == -1 + && (h->def_dynamic + || h->ref_dynamic)) + { + if (! bfd_elf_link_record_dynamic_symbol (eif->info, h)) + { + eif->failed = TRUE; + return FALSE; + } + } + } + else + { + /* Unfortunately, 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->def_regular + && (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->def_dynamic))) + h->def_regular = 1; + } + + /* Backend specific symbol fixup. */ + if (elf_hash_table (eif->info)->dynobj) + { + bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj); + if (bed->elf_backend_fixup_symbol + && !(*bed->elf_backend_fixup_symbol) (eif->info, h)) + return FALSE; + } + + /* 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 DEF_REGULAR + flag will not have been set. */ + if (h->root.type == bfd_link_hash_defined + && !h->def_regular + && h->ref_regular + && !h->def_dynamic + && (h->root.u.def.section->owner->flags & DYNAMIC) == 0) + h->def_regular = 1; + + /* 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. Likewise, if the symbol has non-default + visibility. If the symbol has hidden or internal visibility, we + will force it local. */ + if (h->needs_plt + && eif->info->shared + && is_elf_hash_table (eif->info->hash) + && (eif->info->symbolic + || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) + && h->def_regular) + { + bfd_boolean force_local; + + 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 a weak undefined symbol has non-default visibility, we also + hide it from the dynamic linker. */ + if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT + && h->root.type == bfd_link_hash_undefweak) + { + const struct elf_backend_data *bed; + bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj); + (*bed->elf_backend_hide_symbol) (eif->info, h, TRUE); + } + + /* 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->u.weakdef != NULL) + { + struct elf_link_hash_entry *weakdef; + + weakdef = h->u.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->def_dynamic); + + /* If the real definition is defined by a regular object file, + don't do anything special. See the longer description in + _bfd_elf_adjust_dynamic_symbol, below. */ + if (weakdef->def_regular) + h->u.weakdef = NULL; + else + (*bed->elf_backend_copy_indirect_symbol) (eif->info, 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. */ + +bfd_boolean +_bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data) +{ + struct elf_info_failed *eif = data; + bfd *dynobj; + const struct elf_backend_data *bed; + + if (! is_elf_hash_table (eif->info->hash)) + return FALSE; + + if (h->root.type == bfd_link_hash_warning) + { + h->got = elf_hash_table (eif->info)->init_got_offset; + h->plt = elf_hash_table (eif->info)->init_plt_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 (! _bfd_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->needs_plt + && (h->def_regular + || !h->def_dynamic + || (!h->ref_regular + && (h->u.weakdef == NULL || h->u.weakdef->dynindx == -1)))) + { + h->plt = elf_hash_table (eif->info)->init_plt_offset; + return TRUE; + } + + /* If we've already adjusted this symbol, don't do it again. This + can happen via a recursive call. */ + if (h->dynamic_adjusted) + 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->dynamic_adjusted = 1; + + /* 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->u.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->U.WEAKDEF before it finds H? */ + h->u.weakdef->ref_regular = 1; + + if (! _bfd_elf_adjust_dynamic_symbol (h->u.weakdef, 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->needs_plt) + (*_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; +} + +/* Adjust all external symbols pointing into SEC_MERGE sections + to reflect the object merging within the sections. */ + +bfd_boolean +_bfd_elf_link_sec_merge_syms (struct elf_link_hash_entry *h, void *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 = 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); + } + + return TRUE; +} + +/* Returns false if the symbol referred to by H should be considered + to resolve local to the current module, and true if it should be + considered to bind dynamically. */ + +bfd_boolean +_bfd_elf_dynamic_symbol_p (struct elf_link_hash_entry *h, + struct bfd_link_info *info, + bfd_boolean ignore_protected) +{ + bfd_boolean binding_stays_local_p; + + if (h == NULL) + return FALSE; + + 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 it was forced local, then clearly it's not dynamic. */ + if (h->dynindx == -1) + return FALSE; + if (h->forced_local) + return FALSE; + + /* Identify the cases where name binding rules say that a + visible symbol resolves locally. */ + binding_stays_local_p = info->executable || info->symbolic; + + switch (ELF_ST_VISIBILITY (h->other)) + { + case STV_INTERNAL: + case STV_HIDDEN: + return FALSE; + + case STV_PROTECTED: + /* Proper resolution for function pointer equality may require + that these symbols perhaps be resolved dynamically, even though + we should be resolving them to the current module. */ + if (!ignore_protected || h->type != STT_FUNC) + binding_stays_local_p = TRUE; + break; + + default: + break; + } + + /* If it isn't defined locally, then clearly it's dynamic. */ + if (!h->def_regular) + return TRUE; + + /* Otherwise, the symbol is dynamic if binding rules don't tell + us that it remains local. */ + return !binding_stays_local_p; +} + +/* Return true if the symbol referred to by H should be considered + to resolve local to the current module, and false otherwise. Differs + from (the inverse of) _bfd_elf_dynamic_symbol_p in the treatment of + undefined symbols and weak symbols. */ + +bfd_boolean +_bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h, + struct bfd_link_info *info, + bfd_boolean local_protected) +{ + /* If it's a local sym, of course we resolve locally. */ + if (h == NULL) + return TRUE; + + /* Common symbols that become definitions don't get the DEF_REGULAR + flag set, so test it first, and don't bail out. */ + if (ELF_COMMON_DEF_P (h)) + /* Do nothing. */; + /* If we don't have a definition in a regular file, then we can't + resolve locally. The sym is either undefined or dynamic. */ + else if (!h->def_regular) + return FALSE; + + /* Forced local symbols resolve locally. */ + if (h->forced_local) + return TRUE; + + /* As do non-dynamic symbols. */ + if (h->dynindx == -1) + return TRUE; + + /* At this point, we know the symbol is defined and dynamic. In an + executable it must resolve locally, likewise when building symbolic + shared libraries. */ + if (info->executable || info->symbolic) + return TRUE; + + /* Now deal with defined dynamic symbols in shared libraries. Ones + with default visibility might not resolve locally. */ + if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) + return FALSE; + + /* However, STV_HIDDEN or STV_INTERNAL ones must be local. */ + if (ELF_ST_VISIBILITY (h->other) != STV_PROTECTED) + return TRUE; + + /* STV_PROTECTED non-function symbols are local. */ + if (h->type != STT_FUNC) + return TRUE; + + /* Function pointer equality tests may require that STV_PROTECTED + symbols be treated as dynamic symbols, even when we know that the + dynamic linker will resolve them locally. */ + return local_protected; +} + +/* Caches some TLS segment info, and ensures that the TLS segment vma is + aligned. Returns the first TLS output section. */ + +struct bfd_section * +_bfd_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) +{ + struct bfd_section *sec, *tls; + unsigned int align = 0; + + for (sec = obfd->sections; sec != NULL; sec = sec->next) + if ((sec->flags & SEC_THREAD_LOCAL) != 0) + break; + tls = sec; + + for (; sec != NULL && (sec->flags & SEC_THREAD_LOCAL) != 0; sec = sec->next) + if (sec->alignment_power > align) + align = sec->alignment_power; + + elf_hash_table (info)->tls_sec = tls; + + /* Ensure the alignment of the first section is the largest alignment, + so that the tls segment starts aligned. */ + if (tls != NULL) + tls->alignment_power = align; + + return tls; +} + +/* Return TRUE iff this is a non-common, definition of a non-function symbol. */ +static bfd_boolean +is_global_data_symbol_definition (bfd *abfd ATTRIBUTE_UNUSED, + Elf_Internal_Sym *sym) +{ + const struct elf_backend_data *bed; + + /* 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. */ + bed = get_elf_backend_data (abfd); + if (bed->common_definition (sym)) + 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 (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 == 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 / get_elf_backend_data (abfd)->s->sizeof_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 == NULL) + break; + + if (strcmp (name, symdef->name) == 0) + { + result = is_global_data_symbol_definition (abfd, isym); + break; + } + } + + free (isymbuf); + + return result; +} + +/* Add an entry to the .dynamic table. */ + +bfd_boolean +_bfd_elf_add_dynamic_entry (struct bfd_link_info *info, + bfd_vma tag, + bfd_vma val) +{ + struct elf_link_hash_table *hash_table; + const struct elf_backend_data *bed; + asection *s; + bfd_size_type newsize; + bfd_byte *newcontents; + Elf_Internal_Dyn dyn; + + hash_table = elf_hash_table (info); + if (! is_elf_hash_table (hash_table)) + return FALSE; + + bed = get_elf_backend_data (hash_table->dynobj); + s = bfd_get_section_by_name (hash_table->dynobj, ".dynamic"); + BFD_ASSERT (s != NULL); + + newsize = s->size + bed->s->sizeof_dyn; + newcontents = bfd_realloc (s->contents, newsize); + if (newcontents == NULL) + return FALSE; + + dyn.d_tag = tag; + dyn.d_un.d_val = val; + bed->s->swap_dyn_out (hash_table->dynobj, &dyn, newcontents + s->size); + + s->size = newsize; + s->contents = newcontents; + + return TRUE; +} + +/* Add a DT_NEEDED entry for this dynamic object if DO_IT is true, + otherwise just check whether one already exists. Returns -1 on error, + 1 if a DT_NEEDED tag already exists, and 0 on success. */ + +static int +elf_add_dt_needed_tag (bfd *abfd, + struct bfd_link_info *info, + const char *soname, + bfd_boolean do_it) +{ + struct elf_link_hash_table *hash_table; + bfd_size_type oldsize; + bfd_size_type strindex; + + if (!_bfd_elf_link_create_dynstrtab (abfd, info)) + return -1; + + hash_table = elf_hash_table (info); + oldsize = _bfd_elf_strtab_size (hash_table->dynstr); + strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, FALSE); + if (strindex == (bfd_size_type) -1) + return -1; + + if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr)) + { + asection *sdyn; + const struct elf_backend_data *bed; + bfd_byte *extdyn; + + bed = get_elf_backend_data (hash_table->dynobj); + sdyn = bfd_get_section_by_name (hash_table->dynobj, ".dynamic"); + if (sdyn != NULL) + for (extdyn = sdyn->contents; + extdyn < sdyn->contents + sdyn->size; + extdyn += bed->s->sizeof_dyn) + { + Elf_Internal_Dyn dyn; + + bed->s->swap_dyn_in (hash_table->dynobj, extdyn, &dyn); + if (dyn.d_tag == DT_NEEDED + && dyn.d_un.d_val == strindex) + { + _bfd_elf_strtab_delref (hash_table->dynstr, strindex); + return 1; + } + } + } + + if (do_it) + { + if (!_bfd_elf_link_create_dynamic_sections (hash_table->dynobj, info)) + return -1; + + if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex)) + return -1; + } + else + /* We were just checking for existence of the tag. */ + _bfd_elf_strtab_delref (hash_table->dynstr, strindex); + + return 0; +} + +/* Sort symbol by value and section. */ +static int +elf_sort_symbol (const void *arg1, const void *arg2) +{ + const struct elf_link_hash_entry *h1; + const struct elf_link_hash_entry *h2; + bfd_signed_vma vdiff; + + h1 = *(const struct elf_link_hash_entry **) arg1; + h2 = *(const struct elf_link_hash_entry **) arg2; + vdiff = h1->root.u.def.value - h2->root.u.def.value; + if (vdiff != 0) + return vdiff > 0 ? 1 : -1; + else + { + long sdiff = h1->root.u.def.section->id - h2->root.u.def.section->id; + if (sdiff != 0) + return sdiff > 0 ? 1 : -1; + } + return 0; +} + +/* 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 (struct elf_link_hash_entry *h, void *data) +{ + struct elf_strtab_hash *dynstr = 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 (bfd *output_bfd, struct bfd_link_info *info) +{ + struct elf_link_hash_table *hash_table = elf_hash_table (info); + struct elf_link_local_dynamic_entry *entry; + struct elf_strtab_hash *dynstr = hash_table->dynstr; + bfd *dynobj = hash_table->dynobj; + asection *sdyn; + bfd_size_type size; + const struct elf_backend_data *bed; + bfd_byte *extdyn; + + _bfd_elf_strtab_finalize (dynstr); + size = _bfd_elf_strtab_size (dynstr); + + bed = get_elf_backend_data (dynobj); + sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + BFD_ASSERT (sdyn != NULL); + + /* Update all .dynamic entries referencing .dynstr strings. */ + for (extdyn = sdyn->contents; + extdyn < sdyn->contents + sdyn->size; + extdyn += bed->s->sizeof_dyn) + { + Elf_Internal_Dyn dyn; + + bed->s->swap_dyn_in (dynobj, extdyn, &dyn); + switch (dyn.d_tag) + { + case DT_STRSZ: + dyn.d_un.d_val = size; + 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); + break; + default: + continue; + } + bed->s->swap_dyn_out (dynobj, &dyn, extdyn); + } + + /* Now update local dynamic symbols. */ + for (entry = hash_table->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 (hash_table, 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 = s->contents; + do + { + _bfd_elf_swap_verdef_in (output_bfd, (Elf_External_Verdef *) p, + &def); + p += sizeof (Elf_External_Verdef); + if (def.vd_aux != sizeof (Elf_External_Verdef)) + continue; + 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 = 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; +} + +/* Add symbols from an ELF object file to the linker hash table. */ + +static bfd_boolean +elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) +{ + 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; + const struct elf_backend_data *bed; + bfd_boolean add_needed; + struct elf_link_hash_table *htab; + bfd_size_type amt; + void *alloc_mark = NULL; + void *old_tab = NULL; + void *old_hash; + void *old_ent; + struct bfd_link_hash_entry *old_undefs = NULL; + struct bfd_link_hash_entry *old_undefs_tail = NULL; + long old_dynsymcount = 0; + size_t tabsize = 0; + size_t hashsize = 0; + + htab = elf_hash_table (info); + bed = get_elf_backend_data (abfd); + + 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->relocatable + || !is_elf_hash_table (htab) + || htab->root.creator != abfd->xvec) + { + if (info->relocatable) + bfd_set_error (bfd_error_invalid_operation); + else + bfd_set_error (bfd_error_wrong_format); + 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->executable) + { + 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) + { + struct elf_link_hash_entry *h; + + h = elf_link_hash_lookup (htab, name, FALSE, FALSE, TRUE); + + /* FIXME: What about bfd_link_hash_common? */ + if (h != NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)) + { + /* We don't want to issue this warning. Clobber + the section size so that the warning does not + get copied into the output file. */ + s->size = 0; + continue; + } + } + + sz = s->size; + msg = bfd_alloc (abfd, sz + 1); + if (msg == NULL) + goto error_return; + + if (! bfd_get_section_contents (abfd, s, msg, 0, sz)) + goto error_return; + + msg[sz] = '\0'; + + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, name, BSF_WARNING, s, 0, msg, + FALSE, bed->collect, NULL))) + goto error_return; + + if (! info->relocatable) + { + /* Clobber the section size so that the warning does + not get copied into the output file. */ + s->size = 0; + + /* Also set SEC_EXCLUDE, so that symbols defined in + the warning section don't get copied to the output. */ + s->flags |= SEC_EXCLUDE; + } + } + } + } + + add_needed = TRUE; + if (! dynamic) + { + /* If we are creating a shared library, create all the dynamic + sections immediately. We need to attach them to something, + so we attach them to this BFD, provided it is the right + format. FIXME: If there are no input BFD's of the same + format as the output, we can't make a shared library. */ + if (info->shared + && is_elf_hash_table (htab) + && htab->root.creator == abfd->xvec + && !htab->dynamic_sections_created) + { + if (! _bfd_elf_link_create_dynamic_sections (abfd, info)) + goto error_return; + } + } + else if (!is_elf_hash_table (htab)) + goto error_return; + else + { + asection *s; + const char *soname = NULL; + struct bfd_link_needed_list *rpath = NULL, *runpath = NULL; + int ret; + + /* ld --just-symbols and dynamic objects don't mix very well. + ld shouldn't allow it. */ + if ((s = abfd->sections) != NULL + && s->sec_info_type == ELF_INFO_TYPE_JUST_SYMS) + abort (); + + /* If this dynamic lib was specified on the command line with + --as-needed in effect, then we don't want to add a DT_NEEDED + tag unless the lib is actually used. Similary for libs brought + in by another lib's DT_NEEDED. When --no-add-needed is used + on a dynamic lib, we don't want to add a DT_NEEDED entry for + any dynamic library in DT_NEEDED tags in the dynamic lib at + all. */ + add_needed = (elf_dyn_lib_class (abfd) + & (DYN_AS_NEEDED | DYN_DT_NEEDED + | DYN_NO_NEEDED)) == 0; + + s = bfd_get_section_by_name (abfd, ".dynamic"); + if (s != NULL) + { + bfd_byte *dynbuf; + bfd_byte *extdyn; + int elfsec; + unsigned long shlink; + + if (!bfd_malloc_and_get_section (abfd, s, &dynbuf)) + 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; + + for (extdyn = dynbuf; + extdyn < dynbuf + s->size; + extdyn += bed->s->sizeof_dyn) + { + Elf_Internal_Dyn dyn; + + bed->s->swap_dyn_in (abfd, extdyn, &dyn); + if (dyn.d_tag == DT_SONAME) + { + unsigned int tagv = dyn.d_un.d_val; + soname = bfd_elf_string_from_elf_section (abfd, shlink, tagv); + if (soname == 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 = 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, amt); + n->name = anm; + n->by = abfd; + n->next = NULL; + for (pn = &htab->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 = 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, 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 = 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, 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 = &htab->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); + + /* 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 (soname == NULL || *soname == '\0') + { + soname = elf_dt_name (abfd); + if (soname == NULL || *soname == '\0') + soname = bfd_get_filename (abfd); + } + + /* Save the SONAME because sometimes the linker emulation code + will need to know it. */ + elf_dt_name (abfd) = soname; + + ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed); + if (ret < 0) + goto error_return; + + /* 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. */ + if (ret > 0) + return TRUE; + } + + /* 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 / bed->s->sizeof_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 = 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, + info->default_imported_symver)) + 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 = 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 (extversym, amt, abfd) != amt) + goto error_free_vers; + } + } + + /* If we are loading an as-needed shared lib, save the symbol table + state before we start adding symbols. If the lib turns out + to be unneeded, restore the state. */ + if ((elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0) + { + unsigned int i; + size_t entsize; + + for (entsize = 0, i = 0; i < htab->root.table.size; i++) + { + struct bfd_hash_entry *p; + struct elf_link_hash_entry *h; + + for (p = htab->root.table.table[i]; p != NULL; p = p->next) + { + h = (struct elf_link_hash_entry *) p; + entsize += htab->root.table.entsize; + if (h->root.type == bfd_link_hash_warning) + entsize += htab->root.table.entsize; + } + } + + tabsize = htab->root.table.size * sizeof (struct bfd_hash_entry *); + hashsize = extsymcount * sizeof (struct elf_link_hash_entry *); + old_tab = bfd_malloc (tabsize + entsize + hashsize); + if (old_tab == NULL) + goto error_free_vers; + + /* Remember the current objalloc pointer, so that all mem for + symbols added can later be reclaimed. */ + alloc_mark = bfd_hash_allocate (&htab->root.table, 1); + if (alloc_mark == NULL) + goto error_free_vers; + + /* Clone the symbol table and sym hashes. Remember some + pointers into the symbol table, and dynamic symbol count. */ + old_hash = (char *) old_tab + tabsize; + old_ent = (char *) old_hash + hashsize; + memcpy (old_tab, htab->root.table.table, tabsize); + memcpy (old_hash, sym_hash, hashsize); + old_undefs = htab->root.undefs; + old_undefs_tail = htab->root.undefs_tail; + old_dynsymcount = htab->dynsymcount; + + for (i = 0; i < htab->root.table.size; i++) + { + struct bfd_hash_entry *p; + struct elf_link_hash_entry *h; + + for (p = htab->root.table.table[i]; p != NULL; p = p->next) + { + memcpy (old_ent, p, htab->root.table.entsize); + old_ent = (char *) old_ent + htab->root.table.entsize; + h = (struct elf_link_hash_entry *) p; + if (h->root.type == bfd_link_hash_warning) + { + memcpy (old_ent, h->root.u.i.link, htab->root.table.entsize); + old_ent = (char *) old_ent + htab->root.table.entsize; + } + } + } + } + + 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, *new_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; + bfd_boolean common; + unsigned int old_alignment; + bfd *old_bfd; + + override = FALSE; + + flags = BSF_NO_FLAGS; + sec = NULL; + value = isym->st_value; + *sym_hash = NULL; + common = bed->common_definition (isym); + + bind = ELF_ST_BIND (isym->st_info); + 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. Unfortunately, Irix 5 + screws this up. */ + continue; + } + else if (bind == STB_GLOBAL) + { + if (isym->st_shndx != SHN_UNDEF && !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 = bfd_section_from_elf_index (abfd, isym->st_shndx); + if (sec == NULL) + sec = bfd_abs_section_ptr; + else if (sec->kept_section) + { + /* Symbols from discarded section are undefined, and have + default visibility. */ + sec = bfd_und_section_ptr; + isym->st_shndx = SHN_UNDEF; + isym->st_other = (STV_DEFAULT + | (isym->st_other & ~ ELF_ST_VISIBILITY (-1))); + } + 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 == 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_with_flags (abfd, ".tcommon", + (SEC_ALLOC + | SEC_IS_COMMON + | SEC_LINKER_CREATED + | SEC_THREAD_LOCAL)); + if (tcomm == NULL) + goto error_free_vers; + } + sec = tcomm; + } + else if (bed->elf_add_symbol_hook) + { + if (! (*bed->elf_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 == NULL) + continue; + } + + /* Sanity check that all possibilities were handled. */ + if (sec == 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 = bed->type_change_ok; + old_alignment = 0; + old_bfd = NULL; + new_sec = sec; + + if (is_elf_hash_table (htab)) + { + Elf_Internal_Versym iver; + unsigned int vernum = 0; + bfd_boolean skip; + + if (ever == NULL) + { + if (info->default_imported_symver) + /* Use the default symbol version created earlier. */ + iver.vs_vers = elf_tdata (abfd)->cverdefs; + else + iver.vs_vers = 0; + } + else + _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 + if it is not a function, 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) + || ELF_ST_TYPE (isym->st_info) == STT_FUNC))) + { + const char *verstr; + size_t namelen, verlen, newlen; + char *newname, *p; + + if (isym->st_shndx != SHN_UNDEF) + { + if (vernum > elf_tdata (abfd)->cverdefs) + verstr = NULL; + else if (vernum > 1) + verstr = + elf_tdata (abfd)->verdef[vernum - 1].vd_nodename; + else + verstr = ""; + + if (verstr == NULL) + { + (*_bfd_error_handler) + (_("%B: %s: invalid version %u (max %d)"), + abfd, name, vernum, + elf_tdata (abfd)->cverdefs); + bfd_set_error (bfd_error_bad_value); + goto error_free_vers; + } + } + 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) + (_("%B: %s: invalid needed version %d"), + 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 = bfd_hash_allocate (&htab->root.table, 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 (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, + &value, &old_alignment, + sym_hash, &skip, &override, + &type_change_ok, &size_change_ok)) + 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, NULL, FALSE, bed->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 + && is_elf_hash_table (htab) + && h->u.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->u.weakdef = weaks; + weaks = h; + new_weakdef = TRUE; + } + + /* Set the alignment of a common symbol. */ + if ((common || bfd_is_com_section (sec)) + && h->root.type == bfd_link_hash_common) + { + unsigned int align; + + if (common) + align = bfd_log2 (isym->st_value); + else + { + /* The new symbol is a common symbol in a shared object. + We need to get the alignment from the section. */ + align = new_sec->alignment_power; + } + 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 (is_elf_hash_table (htab)) + { + bfd_boolean dynsym; + + /* Check the alignment when a common symbol is involved. This + can change when a common symbol is overridden 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 || 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 != NULL + && (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 %B" + " is smaller than %u in %B"), + normal_bfd, common_bfd, + 1 << normal_align, name, 1 << common_align); + } + + /* 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 %B to %lu in %B"), + old_bfd, abfd, + name, (unsigned long) h->size, + (unsigned long) isym->st_size); + + 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 %B"), + abfd, name, h->type, ELF_ST_TYPE (isym->st_info)); + + 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 (bed->elf_backend_merge_symbol_attribute) + (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition, + dynamic); + + /* If this symbol has default visibility and the user has requested + we not re-export it, then mark it as hidden. */ + if (definition && !dynamic + && (abfd->no_export + || (abfd->my_archive && abfd->my_archive->no_export)) + && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL) + isym->st_other = (STV_HIDDEN + | (isym->st_other & ~ELF_ST_VISIBILITY (-1))); + + if (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. */ + dynsym = FALSE; + if (! dynamic) + { + if (! definition) + { + h->ref_regular = 1; + if (bind != STB_WEAK) + h->ref_regular_nonweak = 1; + } + else + h->def_regular = 1; + if (! info->executable + || h->def_dynamic + || h->ref_dynamic) + dynsym = TRUE; + } + else + { + if (! definition) + h->ref_dynamic = 1; + else + h->def_dynamic = 1; + if (h->def_regular + || h->ref_regular + || (h->u.weakdef != NULL + && ! new_weakdef + && h->u.weakdef->dynindx != -1)) + dynsym = TRUE; + } + + /* Check to see if we need to add an indirect symbol for + the default name. */ + if (definition || h->root.type == bfd_link_hash_common) + if (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym, + &sec, &value, &dynsym, + override)) + goto error_free_vers; + + if (definition && !dynamic) + { + char *p = strchr (name, ELF_VER_CHR); + 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->u.weakdef != NULL + && ! new_weakdef + && h->u.weakdef->dynindx == -1) + { + if (!bfd_elf_link_record_dynamic_symbol (info, h->u.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); + dynsym = FALSE; + break; + } + + if (!add_needed + && definition + && dynsym + && h->ref_regular) + { + int ret; + const char *soname = elf_dt_name (abfd); + + /* A symbol from a library loaded via DT_NEEDED of some + other library is referenced by a regular object. + Add a DT_NEEDED entry for it. Issue an error if + --no-add-needed is used. */ + if ((elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0) + { + (*_bfd_error_handler) + (_("%s: invalid DSO for symbol `%s' definition"), + abfd, name); + bfd_set_error (bfd_error_bad_value); + goto error_free_vers; + } + + elf_dyn_lib_class (abfd) &= ~DYN_AS_NEEDED; + + add_needed = TRUE; + ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed); + if (ret < 0) + goto error_free_vers; + + BFD_ASSERT (ret == 0); + } + } + } + + if (extversym != NULL) + { + free (extversym); + extversym = NULL; + } + + if (isymbuf != NULL) + { + free (isymbuf); + isymbuf = NULL; + } + + if ((elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0) + { + unsigned int i; + + /* Restore the symbol table. */ + old_hash = (char *) old_tab + tabsize; + old_ent = (char *) old_hash + hashsize; + sym_hash = elf_sym_hashes (abfd); + memcpy (htab->root.table.table, old_tab, tabsize); + memcpy (sym_hash, old_hash, hashsize); + htab->root.undefs = old_undefs; + htab->root.undefs_tail = old_undefs_tail; + for (i = 0; i < htab->root.table.size; i++) + { + struct bfd_hash_entry *p; + struct elf_link_hash_entry *h; + + for (p = htab->root.table.table[i]; p != NULL; p = p->next) + { + h = (struct elf_link_hash_entry *) p; + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + if (h->dynindx >= old_dynsymcount) + _bfd_elf_strtab_delref (htab->dynstr, h->dynstr_index); + + memcpy (p, old_ent, htab->root.table.entsize); + old_ent = (char *) old_ent + htab->root.table.entsize; + h = (struct elf_link_hash_entry *) p; + if (h->root.type == bfd_link_hash_warning) + { + memcpy (h->root.u.i.link, old_ent, htab->root.table.entsize); + old_ent = (char *) old_ent + htab->root.table.entsize; + } + } + } + + free (old_tab); + objalloc_free_block ((struct objalloc *) htab->root.table.memory, + alloc_mark); + if (nondeflt_vers != NULL) + free (nondeflt_vers); + return TRUE; + } + + if (old_tab != NULL) + { + free (old_tab); + old_tab = NULL; + } + + /* 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 (&htab->root, 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) (info, 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; + } + + /* 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. */ + if (weaks != NULL) + { + struct elf_link_hash_entry **hpp; + struct elf_link_hash_entry **hppend; + struct elf_link_hash_entry **sorted_sym_hash; + struct elf_link_hash_entry *h; + size_t sym_count; + + /* Since we have to search the whole symbol list for each weak + defined symbol, search time for N weak defined symbols will be + O(N^2). Binary search will cut it down to O(NlogN). */ + amt = extsymcount * sizeof (struct elf_link_hash_entry *); + sorted_sym_hash = bfd_malloc (amt); + if (sorted_sym_hash == NULL) + goto error_return; + sym_hash = sorted_sym_hash; + hpp = elf_sym_hashes (abfd); + hppend = hpp + extsymcount; + sym_count = 0; + for (; hpp < hppend; hpp++) + { + h = *hpp; + if (h != NULL + && h->root.type == bfd_link_hash_defined + && h->type != STT_FUNC) + { + *sym_hash = h; + sym_hash++; + sym_count++; + } + } + + qsort (sorted_sym_hash, sym_count, + sizeof (struct elf_link_hash_entry *), + elf_sort_symbol); + + while (weaks != NULL) + { + struct elf_link_hash_entry *hlook; + asection *slook; + bfd_vma vlook; + long ilook; + size_t i, j, idx; + + hlook = weaks; + weaks = hlook->u.weakdef; + hlook->u.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; + + ilook = -1; + i = 0; + j = sym_count; + while (i < j) + { + bfd_signed_vma vdiff; + idx = (i + j) / 2; + h = sorted_sym_hash [idx]; + vdiff = vlook - h->root.u.def.value; + if (vdiff < 0) + j = idx; + else if (vdiff > 0) + i = idx + 1; + else + { + long sdiff = slook->id - h->root.u.def.section->id; + if (sdiff < 0) + j = idx; + else if (sdiff > 0) + i = idx + 1; + else + { + ilook = idx; + break; + } + } + } + + /* We didn't find a value/section match. */ + if (ilook == -1) + continue; + + for (i = ilook; i < sym_count; i++) + { + h = sorted_sym_hash [i]; + + /* Stop if value or section doesn't match. */ + if (h->root.u.def.value != vlook + || h->root.u.def.section != slook) + break; + else if (h != hlook) + { + hlook->u.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; + } + } + } + + free (sorted_sym_hash); + } + + if (bed->check_directives) + (*bed->check_directives) (abfd, info); + + /* 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. */ + if (! dynamic + && is_elf_hash_table (htab) + && htab->root.creator == abfd->xvec + && bed->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 = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL, + info->keep_memory); + if (internal_relocs == NULL) + goto error_return; + + ok = (*bed->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 + && is_elf_hash_table (htab) + && (info->strip != strip_all && info->strip != strip_debugger)) + { + asection *stabstr; + + stabstr = bfd_get_section_by_name (abfd, ".stabstr"); + if (stabstr != NULL) + { + bfd_size_type string_offset = 0; + asection *stab; + + for (stab = abfd->sections; stab; stab = stab->next) + if (strncmp (".stab", stab->name, 5) == 0 + && (!stab->name[5] || + (stab->name[5] == '.' && ISDIGIT (stab->name[6]))) + && (stab->flags & SEC_MERGE) == 0 + && !bfd_is_abs_section (stab->output_section)) + { + struct bfd_elf_section_data *secdata; + + secdata = elf_section_data (stab); + if (! _bfd_link_section_stabs (abfd, &htab->stab_info, stab, + stabstr, &secdata->sec_info, + &string_offset)) + goto error_return; + if (secdata->sec_info) + stab->sec_info_type = ELF_INFO_TYPE_STABS; + } + } + } + + if (is_elf_hash_table (htab) && add_needed) + { + /* Add this bfd to the loaded list. */ + struct elf_link_loaded_list *n; + + n = bfd_alloc (abfd, sizeof (struct elf_link_loaded_list)); + if (n == NULL) + goto error_return; + n->abfd = abfd; + n->next = htab->loaded; + htab->loaded = n; + } + + return TRUE; + + error_free_vers: + if (old_tab != NULL) + free (old_tab); + if (nondeflt_vers != NULL) + free (nondeflt_vers); + if (extversym != NULL) + free (extversym); + error_free_sym: + if (isymbuf != NULL) + free (isymbuf); + error_return: + return FALSE; +} + +/* Return the linker hash table entry of a symbol that might be + satisfied by an archive symbol. Return -1 on error. */ + +struct elf_link_hash_entry * +_bfd_elf_archive_symbol_lookup (bfd *abfd, + struct bfd_link_info *info, + const char *name) +{ + struct elf_link_hash_entry *h; + char *p, *copy; + size_t len, first; + + h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, FALSE); + if (h != NULL) + return h; + + /* 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 (name, ELF_VER_CHR); + if (p == NULL || p[1] != ELF_VER_CHR) + return h; + + /* First check with only one `@'. */ + len = strlen (name); + copy = bfd_alloc (abfd, len); + if (copy == NULL) + return (struct elf_link_hash_entry *) 0 - 1; + + first = p - name + 1; + memcpy (copy, name, first); + memcpy (copy + first, 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); + return h; +} + +/* 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 (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; + const struct elf_backend_data *bed; + struct elf_link_hash_entry * (*archive_symbol_lookup) + (bfd *, struct bfd_link_info *, const char *); + + if (! bfd_has_map (abfd)) + { + /* An empty archive is a special case. */ + if (bfd_openr_next_archived_file (abfd, 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_zmalloc (amt); + included = bfd_zmalloc (amt); + if (defined == NULL || included == NULL) + goto error_return; + + symdefs = bfd_ardata (abfd)->symdefs; + bed = get_elf_backend_data (abfd); + archive_symbol_lookup = bed->elf_backend_archive_symbol_lookup; + + 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 = archive_symbol_lookup (abfd, info, symdef->name); + if (h == (struct elf_link_hash_entry *) 0 - 1) + goto error_return; + + 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 == 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 (! bfd_link_add_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 != NULL) + free (defined); + if (included != NULL) + free (included); + return FALSE; +} + +/* Given an ELF BFD, add symbols to the global hash table as + appropriate. */ + +bfd_boolean +bfd_elf_link_add_symbols (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; + } +} + +/* 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 (struct elf_link_hash_entry *h, void *data) +{ + unsigned long **valuep = 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 (p - name + 1); + memcpy (alc, name, 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->u.elf_hash_value = ha; + + if (alc != NULL) + free (alc); + + return TRUE; +} + +/* 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 (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 = 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 ; + bfd *dynobj = elf_hash_table (info)->dynobj; + const struct elf_backend_data *bed = get_elf_backend_data (dynobj); + + /* 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 = 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) * (bed->s->arch_size / 8); + +# if 1 + /* Variant 1: optimize for short chains. We add the squares + of all the chain lengths (which favors 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 / (bed->s->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 / (bed->s->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 +bfd_elf_size_dynamic_sections (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; + const struct elf_backend_data *bed; + struct elf_assign_sym_version_info asvinfo; + + *sinterpptr = NULL; + + soname_indx = (bfd_size_type) -1; + + if (!is_elf_hash_table (info->hash)) + return TRUE; + + elf_tdata (output_bfd)->relro = info->relro; + if (info->execstack) + elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X; + else if (info->noexecstack) + elf_tdata (output_bfd)->stack_flags = PF_R | PF_W; + else + { + bfd *inputobj; + asection *notesec = NULL; + int exec = 0; + + for (inputobj = info->input_bfds; + inputobj; + inputobj = inputobj->link_next) + { + asection *s; + + if (inputobj->flags & (DYNAMIC | BFD_LINKER_CREATED)) + continue; + s = bfd_get_section_by_name (inputobj, ".note.GNU-stack"); + if (s) + { + if (s->flags & SEC_CODE) + exec = PF_X; + notesec = s; + } + else + exec = PF_X; + } + if (notesec) + { + elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | exec; + if (exec && info->relocatable + && notesec->output_section != bfd_abs_section_ptr) + notesec->output_section->flags |= SEC_CODE; + } + } + + /* Any syms created from now on start with -1 in + got.refcount/offset and plt.refcount/offset. */ + elf_hash_table (info)->init_got_refcount + = elf_hash_table (info)->init_got_offset; + elf_hash_table (info)->init_plt_refcount + = elf_hash_table (info)->init_plt_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; + asection *s; + bfd_boolean all_defined; + + *sinterpptr = bfd_get_section_by_name (dynobj, ".interp"); + BFD_ASSERT (*sinterpptr != NULL || !info->executable); + + if (soname != NULL) + { + soname_indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, + soname, TRUE); + if (soname_indx == (bfd_size_type) -1 + || !_bfd_elf_add_dynamic_entry (info, DT_SONAME, soname_indx)) + return FALSE; + } + + if (info->symbolic) + { + if (!_bfd_elf_add_dynamic_entry (info, DT_SYMBOLIC, 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 (indx == (bfd_size_type) -1 + || !_bfd_elf_add_dynamic_entry (info, DT_RPATH, indx)) + return FALSE; + + if (info->new_dtags) + { + _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr, indx); + if (!_bfd_elf_add_dynamic_entry (info, 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 + || !_bfd_elf_add_dynamic_entry (info, 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 + || !_bfd_elf_add_dynamic_entry (info, 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), + _bfd_elf_export_symbol, + &eif); + if (eif.failed) + return FALSE; + } + + /* Make all global versions with definition. */ + for (t = verdefs; t != NULL; t = t->next) + for (d = t->globals.list; d != NULL; d = d->next) + if (!d->symver && d->symbol) + { + const char *verstr, *name; + size_t namelen, verlen, newlen; + char *newname, *p; + struct elf_link_hash_entry *newh; + + name = d->symbol; + namelen = strlen (name); + verstr = t->name; + verlen = strlen (verstr); + newlen = namelen + verlen + 3; + + newname = bfd_malloc (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->def_dynamic + && (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), + _bfd_elf_link_assign_sym_version, + &asvinfo); + if (asvinfo.failed) + return FALSE; + + if (!info->allow_undefined_version) + { + /* Check if all global versions have a definition. */ + all_defined = TRUE; + for (t = verdefs; t != NULL; t = t->next) + for (d = t->globals.list; d != NULL; d = d->next) + if (!d->symver && !d->script) + { + (*_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), + _bfd_elf_adjust_dynamic_symbol, + &eif); + if (eif.failed) + return FALSE; + + /* Add some entries to the .dynamic section. We fill in some of the + values later, in bfd_elf_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->ref_regular + || h->def_regular)) + { + if (!_bfd_elf_add_dynamic_entry (info, DT_INIT, 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->ref_regular + || h->def_regular)) + { + if (!_bfd_elf_add_dynamic_entry (info, DT_FINI, 0)) + return FALSE; + } + + s = bfd_get_section_by_name (output_bfd, ".preinit_array"); + if (s != NULL && s->linker_has_input) + { + /* DT_PREINIT_ARRAY is not allowed in shared library. */ + if (! info->executable) + { + 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) + (_("%B: .preinit_array section is not allowed in DSO"), + sub); + break; + } + + bfd_set_error (bfd_error_nonrepresentable_section); + return FALSE; + } + + if (!_bfd_elf_add_dynamic_entry (info, DT_PREINIT_ARRAY, 0) + || !_bfd_elf_add_dynamic_entry (info, DT_PREINIT_ARRAYSZ, 0)) + return FALSE; + } + s = bfd_get_section_by_name (output_bfd, ".init_array"); + if (s != NULL && s->linker_has_input) + { + if (!_bfd_elf_add_dynamic_entry (info, DT_INIT_ARRAY, 0) + || !_bfd_elf_add_dynamic_entry (info, DT_INIT_ARRAYSZ, 0)) + return FALSE; + } + s = bfd_get_section_by_name (output_bfd, ".fini_array"); + if (s != NULL && s->linker_has_input) + { + if (!_bfd_elf_add_dynamic_entry (info, DT_FINI_ARRAY, 0) + || !_bfd_elf_add_dynamic_entry (info, DT_FINI_ARRAYSZ, 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 (!_bfd_elf_add_dynamic_entry (info, DT_HASH, 0) + || !_bfd_elf_add_dynamic_entry (info, DT_STRTAB, 0) + || !_bfd_elf_add_dynamic_entry (info, DT_SYMTAB, 0) + || !_bfd_elf_add_dynamic_entry (info, DT_STRSZ, strsize) + || !_bfd_elf_add_dynamic_entry (info, DT_SYMENT, + bed->s->sizeof_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) + { + unsigned long section_sym_count; + asection *s; + + /* 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 && !info->create_default_symver) + s->flags |= SEC_EXCLUDE; + 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; + struct bfd_link_hash_entry *bh; + struct elf_link_hash_entry *h; + const char *name; + + cdefs = 0; + size = 0; + + /* Make space for the base version. */ + size += sizeof (Elf_External_Verdef); + size += sizeof (Elf_External_Verdaux); + ++cdefs; + + /* Make space for the default version. */ + if (info->create_default_symver) + { + size += sizeof (Elf_External_Verdef); + ++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->size = size; + s->contents = bfd_alloc (output_bfd, s->size); + if (s->contents == NULL && s->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; + if (info->create_default_symver) + { + def.vd_aux = 2 * sizeof (Elf_External_Verdef); + def.vd_next = sizeof (Elf_External_Verdef); + } + else + { + 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; + name = soname; + } + else + { + bfd_size_type indx; + + name = lbasename (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); + if (info->create_default_symver) + { + /* Add a symbol representing this version. */ + bh = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, dynobj, name, BSF_GLOBAL, bfd_abs_section_ptr, + 0, NULL, FALSE, + get_elf_backend_data (dynobj)->collect, &bh))) + return FALSE; + h = (struct elf_link_hash_entry *) bh; + h->non_elf = 0; + h->def_regular = 1; + h->type = STT_OBJECT; + h->verinfo.vertree = NULL; + + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + + /* Create a duplicate of the base version with the same + aux block, but different flags. */ + def.vd_flags = 0; + def.vd_ndx = 2; + def.vd_aux = sizeof (Elf_External_Verdef); + if (verdefs) + def.vd_next = (sizeof (Elf_External_Verdef) + + 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); + } + _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; + + 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, + 0, NULL, FALSE, + get_elf_backend_data (dynobj)->collect, &bh))) + return FALSE; + h = (struct elf_link_hash_entry *) bh; + h->non_elf = 0; + h->def_regular = 1; + 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.list == NULL + && t->locals.list == NULL + && ! t->used) + def.vd_flags |= VER_FLG_WEAK; + def.vd_ndx = t->vernum + (info->create_default_symver ? 2 : 1); + def.vd_cnt = cdeps + 1; + def.vd_hash = bfd_elf_hash (t->name); + def.vd_aux = sizeof (Elf_External_Verdef); + def.vd_next = 0; + if (t->next != NULL) + def.vd_next = (sizeof (Elf_External_Verdef) + + (cdeps + 1) * sizeof (Elf_External_Verdaux)); + + _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); + defaux.vda_next = 0; + if (t->deps != NULL) + 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 (!_bfd_elf_add_dynamic_entry (info, DT_VERDEF, 0) + || !_bfd_elf_add_dynamic_entry (info, DT_VERDEFNUM, cdefs)) + return FALSE; + + elf_tdata (output_bfd)->cverdefs = cdefs; + } + + if ((info->new_dtags && info->flags) || (info->flags & DF_STATIC_TLS)) + { + if (!_bfd_elf_add_dynamic_entry (info, DT_FLAGS, info->flags)) + return FALSE; + } + else if (info->flags & DF_BIND_NOW) + { + if (!_bfd_elf_add_dynamic_entry (info, DT_BIND_NOW, 0)) + return FALSE; + } + + if (info->flags_1) + { + if (info->executable) + info->flags_1 &= ~ (DF_1_INITFIRST + | DF_1_NODELETE + | DF_1_NOOPEN); + if (!_bfd_elf_add_dynamic_entry (info, 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), + _bfd_elf_link_find_version_dependencies, + &sinfo); + + if (elf_tdata (output_bfd)->verref == NULL) + s->flags |= SEC_EXCLUDE; + 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->size = size; + s->contents = bfd_alloc (output_bfd, s->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) + : lbasename (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 (!_bfd_elf_add_dynamic_entry (info, DT_VERNEED, 0) + || !_bfd_elf_add_dynamic_entry (info, DT_VERNEEDNUM, crefs)) + return FALSE; + + elf_tdata (output_bfd)->cverrefs = crefs; + } + } + + if ((elf_tdata (output_bfd)->cverrefs == 0 + && elf_tdata (output_bfd)->cverdefs == 0) + || _bfd_elf_link_renumber_dynsyms (output_bfd, info, + §ion_sym_count) == 0) + { + s = bfd_get_section_by_name (dynobj, ".gnu.version"); + s->flags |= SEC_EXCLUDE; + } + } + return TRUE; +} + +bfd_boolean +bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info) +{ + if (!is_elf_hash_table (info->hash)) + return TRUE; + + if (elf_hash_table (info)->dynamic_sections_created) + { + bfd *dynobj; + const struct elf_backend_data *bed; + asection *s; + bfd_size_type dynsymcount; + unsigned long section_sym_count; + size_t bucketcount = 0; + size_t hash_entry_size; + unsigned int dtagcount; + + dynobj = elf_hash_table (info)->dynobj; + + /* 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, + §ion_sym_count); + + /* 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 + && (s->flags & SEC_EXCLUDE) == 0) + { + s->size = dynsymcount * sizeof (Elf_External_Versym); + s->contents = bfd_zalloc (output_bfd, s->size); + if (s->contents == NULL) + return FALSE; + + if (!_bfd_elf_add_dynamic_entry (info, DT_VERSYM, 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); + bed = get_elf_backend_data (output_bfd); + s->size = dynsymcount * bed->s->sizeof_sym; + + if (dynsymcount != 0) + { + s->contents = bfd_alloc (output_bfd, s->size); + if (s->contents == NULL) + return FALSE; + + /* The first entry in .dynsym is a dummy symbol. + Clear all the section syms, in case we don't output them all. */ + ++section_sym_count; + memset (s->contents, 0, section_sym_count * bed->s->sizeof_sym); + } + + /* 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->size = ((2 + bucketcount + dynsymcount) * hash_entry_size); + s->contents = bfd_zalloc (output_bfd, s->size); + if (s->contents == NULL) + return FALSE; + + bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents); + bfd_put (8 * hash_entry_size, output_bfd, 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->size = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr); + + for (dtagcount = 0; dtagcount <= info->spare_dynamic_tags; ++dtagcount) + if (!_bfd_elf_add_dynamic_entry (info, DT_NULL, 0)) + return FALSE; + } + + 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; + /* Buffer large enough to hold contents of any section. */ + bfd_byte *contents; + /* Buffer large enough to hold external relocs of any section. */ + void *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. */ + bfd_byte *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. */ + bfd_byte *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; +}; + +/* 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; +}; + +/* When performing a relocatable link, the input relocations are + preserved. But, if they reference global symbols, the indices + referenced must be updated. Update all the relocations in + REL_HDR (there are COUNT of them), using the data in REL_HASH. */ + +static void +elf_link_adjust_relocs (bfd *abfd, + Elf_Internal_Shdr *rel_hdr, + unsigned int count, + struct elf_link_hash_entry **rel_hash) +{ + unsigned int i; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + bfd_byte *erela; + void (*swap_in) (bfd *, const bfd_byte *, Elf_Internal_Rela *); + void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *); + bfd_vma r_type_mask; + int r_sym_shift; + + if (rel_hdr->sh_entsize == bed->s->sizeof_rel) + { + swap_in = bed->s->swap_reloc_in; + swap_out = bed->s->swap_reloc_out; + } + else if (rel_hdr->sh_entsize == bed->s->sizeof_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 (); + + if (bed->s->arch_size == 32) + { + r_type_mask = 0xff; + r_sym_shift = 8; + } + else + { + r_type_mask = 0xffffffff; + r_sym_shift = 32; + } + + 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 = ((bfd_vma) (*rel_hash)->indx << r_sym_shift + | (irela[j].r_info & r_type_mask)); + (*swap_out) (abfd, irela, erela); + } +} + +struct elf_link_sort_rela +{ + union { + bfd_vma offset; + bfd_vma sym_mask; + } u; + 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 (const void *A, const void *B) +{ + const struct elf_link_sort_rela *a = A; + const struct elf_link_sort_rela *b = 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 ((a->rela->r_info & a->u.sym_mask) < (b->rela->r_info & b->u.sym_mask)) + return -1; + if ((a->rela->r_info & a->u.sym_mask) > (b->rela->r_info & b->u.sym_mask)) + 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 (const void *A, const void *B) +{ + const struct elf_link_sort_rela *a = A; + const struct elf_link_sort_rela *b = B; + int copya, copyb; + + if (a->u.offset < b->u.offset) + return -1; + if (a->u.offset > b->u.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 (bfd *abfd, struct bfd_link_info *info, asection **psec) +{ + asection *reldyn; + 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; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + int i2e = bed->s->int_rels_per_ext_rel; + void (*swap_in) (bfd *, const bfd_byte *, Elf_Internal_Rela *); + void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *); + struct bfd_link_order *lo; + bfd_vma r_sym_mask; + + reldyn = bfd_get_section_by_name (abfd, ".rela.dyn"); + if (reldyn == NULL || reldyn->size == 0) + { + reldyn = bfd_get_section_by_name (abfd, ".rel.dyn"); + if (reldyn == NULL || reldyn->size == 0) + return 0; + ext_size = bed->s->sizeof_rel; + swap_in = bed->s->swap_reloc_in; + swap_out = bed->s->swap_reloc_out; + } + else + { + ext_size = bed->s->sizeof_rela; + swap_in = bed->s->swap_reloca_in; + swap_out = bed->s->swap_reloca_out; + } + count = reldyn->size / ext_size; + + size = 0; + for (lo = reldyn->map_head.link_order; lo != NULL; lo = lo->next) + if (lo->type == bfd_indirect_link_order) + { + asection *o = lo->u.indirect.section; + size += o->size; + } + + if (size != reldyn->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, 0); + return 0; + } + + if (bed->s->arch_size == 32) + r_sym_mask = ~(bfd_vma) 0xff; + else + r_sym_mask = ~(bfd_vma) 0xffffffff; + + for (lo = reldyn->map_head.link_order; lo != NULL; lo = lo->next) + if (lo->type == bfd_indirect_link_order) + { + bfd_byte *erel, *erelend; + asection *o = lo->u.indirect.section; + + if (o->contents == NULL && o->size != 0) + { + /* This is a reloc section that is being handled as a normal + section. See bfd_section_from_shdr. We can't combine + relocs in this case. */ + free (sort); + return 0; + } + erel = o->contents; + erelend = o->contents + o->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); + s->u.sym_mask = r_sym_mask; + p += sort_elt; + erel += ext_size; + } + } + + qsort (sort, 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 (((sp->rela->r_info ^ sq->rela->r_info) & r_sym_mask) != 0) + sq = sp; + sp->u.offset = sq->rela->r_offset; + } + + qsort (s_non_relative, count - ret, sort_elt, elf_link_sort_cmp2); + + for (lo = reldyn->map_head.link_order; lo != NULL; lo = lo->next) + if (lo->type == bfd_indirect_link_order) + { + bfd_byte *erel, *erelend; + asection *o = lo->u.indirect.section; + + erel = o->contents; + erelend = o->contents + o->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; +} + +/* Flush the output symbols to the file. */ + +static bfd_boolean +elf_link_flush_output_syms (struct elf_final_link_info *finfo, + const struct elf_backend_data *bed) +{ + 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 * bed->s->sizeof_sym; + if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0 + || bfd_bwrite (finfo->symbuf, amt, finfo->output_bfd) != amt) + return FALSE; + + hdr->sh_size += amt; + finfo->symbuf_count = 0; + } + + return TRUE; +} + +/* Add a symbol to the output symbol table. */ + +static bfd_boolean +elf_link_output_sym (struct elf_final_link_info *finfo, + const char *name, + Elf_Internal_Sym *elfsym, + asection *input_sec, + struct elf_link_hash_entry *h) +{ + bfd_byte *dest; + Elf_External_Sym_Shndx *destshndx; + bfd_boolean (*output_symbol_hook) + (struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *, + struct elf_link_hash_entry *); + const struct elf_backend_data *bed; + + bed = get_elf_backend_data (finfo->output_bfd); + output_symbol_hook = bed->elf_backend_link_output_symbol_hook; + if (output_symbol_hook != NULL) + { + if (! (*output_symbol_hook) (finfo->info, name, elfsym, input_sec, h)) + return FALSE; + } + + if (name == 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, bed)) + return FALSE; + } + + dest = finfo->symbuf + finfo->symbuf_count * bed->s->sizeof_sym; + 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); + } + + bed->s->swap_symbol_out (finfo->output_bfd, elfsym, dest, destshndx); + finfo->symbuf_count += 1; + bfd_get_symcount (finfo->output_bfd) += 1; + + return TRUE; +} + +/* Return TRUE if the dynamic symbol SYM in ABFD is supported. */ + +static bfd_boolean +check_dynsym (bfd *abfd, Elf_Internal_Sym *sym) +{ + if (sym->st_shndx > SHN_HIRESERVE) + { + /* The gABI doesn't support dynamic symbols in output sections + beyond 64k. */ + (*_bfd_error_handler) + (_("%B: Too many sections: %d (>= %d)"), + abfd, bfd_count_sections (abfd), SHN_LORESERVE); + bfd_set_error (bfd_error_nonrepresentable_section); + return FALSE; + } + 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 (struct bfd_link_info *info, + const struct elf_backend_data *bed, + struct elf_link_hash_entry *h) +{ + bfd *abfd; + struct elf_link_loaded_list *loaded; + + if (!is_elf_hash_table (info->hash)) + 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_dyn_lib_class (abfd) & DYN_DT_NEEDED) == 0) + 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 / bed->s->sizeof_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 = bfd_malloc (versymhdr->sh_size); + if (extversym == NULL) + goto error_ret; + + if (bfd_seek (input, versymhdr->sh_offset, SEEK_SET) != 0 + || (bfd_bread (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; + unsigned short version_index; + + 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 (); + } + + version_index = iver.vs_vers & VERSYM_VERSION; + if (version_index == 1 || version_index == 2) + { + /* This is the base or first version. 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 (struct elf_link_hash_entry *h, void *data) +{ + struct elf_outext_info *eoinfo = data; + struct elf_final_link_info *finfo = eoinfo->finfo; + bfd_boolean strip; + Elf_Internal_Sym sym; + asection *input_sec; + const struct elf_backend_data *bed; + + 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->forced_local) + return TRUE; + } + else + { + if (h->forced_local) + return TRUE; + } + + bed = get_elf_backend_data (finfo->output_bfd); + + if (h->root.type == bfd_link_hash_undefined) + { + /* If we have an undefined symbol reference here then it must have + come from a shared library that is being linked in. (Undefined + references in regular files have already been handled). */ + bfd_boolean ignore_undef = FALSE; + + /* Some symbols may be special in that the fact that they're + undefined can be safely ignored - let backend determine that. */ + if (bed->elf_backend_ignore_undef_symbol) + ignore_undef = bed->elf_backend_ignore_undef_symbol (h); + + /* If we are reporting errors for this situation then do so now. */ + if (ignore_undef == FALSE + && h->ref_dynamic + && ! h->ref_regular + && ! elf_link_check_versioned_symbol (finfo->info, bed, h) + && finfo->info->unresolved_syms_in_shared_libs != RM_IGNORE) + { + if (! (finfo->info->callbacks->undefined_symbol + (finfo->info, h->root.root.string, h->root.u.undef.abfd, + NULL, 0, finfo->info->unresolved_syms_in_shared_libs == RM_GENERATE_ERROR))) + { + eoinfo->failed = TRUE; + return FALSE; + } + } + } + + /* We should also warn if a forced local symbol is referenced from + shared libraries. */ + if (! finfo->info->relocatable + && (! finfo->info->shared) + && h->forced_local + && h->ref_dynamic + && !h->dynamic_def + && !h->dynamic_weak + && ! elf_link_check_versioned_symbol (finfo->info, bed, h)) + { + (*_bfd_error_handler) + (_("%B: %s symbol `%s' in %B is referenced by DSO"), + finfo->output_bfd, + h->root.u.def.section == bfd_abs_section_ptr + ? finfo->output_bfd : h->root.u.def.section->owner, + ELF_ST_VISIBILITY (h->other) == STV_INTERNAL + ? "internal" + : ELF_ST_VISIBILITY (h->other) == STV_HIDDEN + ? "hidden" : "local", + h->root.root.string); + 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->def_dynamic + || h->ref_dynamic + || h->root.type == bfd_link_hash_new) + && !h->def_regular + && !h->ref_regular) + 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->forced_local) + return TRUE; + + sym.st_value = 0; + sym.st_size = h->size; + sym.st_other = h->other; + if (h->forced_local) + 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) + (_("%B: could not find output section %A for input section %A"), + finfo->output_bfd, input_sec->output_section, input_sec); + eoinfo->failed = TRUE; + return FALSE; + } + + /* ELF symbols in relocatable files are section relative, + but in nonrelocatable files they are virtual + addresses. */ + sym.st_value = h->root.u.def.value + input_sec->output_offset; + if (! finfo->info->relocatable) + { + 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 (elf_hash_table (finfo->info)->tls_sec != NULL); + sym.st_value -= elf_hash_table (finfo->info)->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 = bed->common_section_index (input_sec); + 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->forced_local) + && ((finfo->info->shared + && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak)) + || !h->forced_local) + && elf_hash_table (finfo->info)->dynamic_sections_created) + { + 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->ref_regular + && (ELF_ST_BIND (sym.st_info) == STB_GLOBAL + || ELF_ST_BIND (sym.st_info) == STB_WEAK)) + { + int bindtype; + + if (h->ref_regular_nonweak) + 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->relocatable + && ELF_ST_VISIBILITY (sym.st_other) != STV_DEFAULT + && ELF_ST_BIND (sym.st_info) != STB_WEAK + && h->root.type == bfd_link_hash_undefined + && !h->def_regular) + { + (*_bfd_error_handler) + (_("%B: %s symbol `%s' isn't defined"), + 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; + bfd_byte *esym; + + sym.st_name = h->dynstr_index; + esym = finfo->dynsym_sec->contents + h->dynindx * bed->s->sizeof_sym; + if (! check_dynsym (finfo->output_bfd, &sym)) + { + eoinfo->failed = TRUE; + return FALSE; + } + bed->s->swap_symbol_out (finfo->output_bfd, &sym, esym, 0); + + bucketcount = elf_hash_table (finfo->info)->bucketcount; + bucket = h->u.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, 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->def_regular) + { + 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 (finfo->info->create_default_symver) + iversym.vs_vers++; + } + + if (h->hidden) + 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, h)) + { + eoinfo->failed = TRUE; + return FALSE; + } + + return TRUE; +} + +/* Return TRUE if special handling is done for relocs in SEC against + symbols defined in discarded sections. */ + +static bfd_boolean +elf_section_ignore_discarded_relocs (asection *sec) +{ + const 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; +} + +/* Return a mask saying how ld should treat relocations in SEC against + symbols defined in discarded sections. If this function returns + COMPLAIN set, ld will issue a warning message. If this function + returns PRETEND set, and the discarded section was link-once and the + same size as the kept link-once section, ld will pretend that the + symbol was actually defined in the kept section. Otherwise ld will + zero the reloc (at least that is the intent, but some cooperation by + the target dependent code is needed, particularly for REL targets). */ + +unsigned int +_bfd_elf_default_action_discarded (asection *sec) +{ + if (sec->flags & SEC_DEBUGGING) + return PRETEND; + + if (strcmp (".eh_frame", sec->name) == 0) + return 0; + + if (strcmp (".gcc_except_table", sec->name) == 0) + return 0; + + return COMPLAIN | PRETEND; +} + +/* Find a match between a section and a member of a section group. */ + +static asection * +match_group_member (asection *sec, asection *group) +{ + asection *first = elf_next_in_group (group); + asection *s = first; + + while (s != NULL) + { + if (bfd_elf_match_symbols_in_sections (s, sec)) + return s; + + s = elf_next_in_group (s); + if (s == first) + break; + } + + return NULL; +} + +/* Check if the kept section of a discarded section SEC can be used + to replace it. Return the replacement if it is OK. Otherwise return + NULL. */ + +asection * +_bfd_elf_check_kept_section (asection *sec) +{ + asection *kept; + + kept = sec->kept_section; + if (kept != NULL) + { + if (elf_sec_group (sec) != NULL) + kept = match_group_member (sec, kept); + if (kept != NULL && sec->size != kept->size) + kept = NULL; + } + return kept; +} + +/* 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 (struct elf_final_link_info *finfo, bfd *input_bfd) +{ + bfd_boolean (*relocate_section) + (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; + const 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->relocatable + || finfo->info->emitrelocations); + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + if (elf_bad_symtab (input_bfd)) + { + locsymcount = symtab_hdr->sh_size / bed->s->sizeof_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 = bfd_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); + } + 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 + { + /* Don't attempt to output symbols with st_shnx in the + reserved range other than SHN_ABS and SHN_COMMON. */ + *ppsection = NULL; + continue; + } + + *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 relocatable 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. */ + if (isym->st_shndx != SHN_UNDEF + && (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE) + && (isec == NULL + || bfd_section_removed_from_list (output_bfd, + isec->output_section))) + 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->relocatable) + || 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 relocatable 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->relocatable) + { + 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 (elf_hash_table (finfo->info)->tls_sec != NULL); + osym.st_value -= elf_hash_table (finfo->info)->tls_sec->vma; + } + } + + if (! elf_link_output_sym (finfo, name, &osym, isec, NULL)) + 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->size == 0 && (o->flags & SEC_RELOC) == 0)) + continue; + + if ((o->flags & SEC_LINKER_CREATED) != 0) + { + /* Section was created by _bfd_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 + { + bfd_size_type amt = o->rawsize ? o->rawsize : o->size; + + contents = finfo->contents; + if (! bfd_get_section_contents (input_bfd, o, contents, 0, amt)) + return FALSE; + } + + if ((o->flags & SEC_RELOC) != 0) + { + Elf_Internal_Rela *internal_relocs; + bfd_vma r_type_mask; + int r_sym_shift; + + /* Get the swapped relocs. */ + internal_relocs + = _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; + + if (bed->s->arch_size == 32) + { + r_type_mask = 0xff; + r_sym_shift = 8; + } + else + { + r_type_mask = 0xffffffff; + r_sym_shift = 32; + } + + /* 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 (!elf_section_ignore_discarded_relocs (o)) + { + Elf_Internal_Rela *rel, *relend; + unsigned int action = (*bed->action_discarded) (o); + + rel = internal_relocs; + relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel; + for ( ; rel < relend; rel++) + { + unsigned long r_symndx = rel->r_info >> r_sym_shift; + asection **ps, *sec; + struct elf_link_hash_entry *h = NULL; + const char *sym_name; + + if (r_symndx == STN_UNDEF) + continue; + + if (r_symndx >= locsymcount + || (elf_bad_symtab (input_bfd) + && finfo->sections[r_symndx] == NULL)) + { + h = sym_hashes[r_symndx - extsymoff]; + + /* Badly formatted input files can contain relocs that + reference non-existant symbols. Check here so that + we do not seg fault. */ + if (h == NULL) + { + char buffer [32]; + + sprintf_vma (buffer, rel->r_info); + (*_bfd_error_handler) + (_("error: %B contains a reloc (0x%s) for section %A " + "that references a non-existent global symbol"), + input_bfd, o, buffer); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + 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) + continue; + + ps = &h->root.u.def.section; + sym_name = h->root.root.string; + } + else + { + Elf_Internal_Sym *sym = isymbuf + r_symndx; + ps = &finfo->sections[r_symndx]; + sym_name = bfd_elf_sym_name (input_bfd, + symtab_hdr, + sym, *ps); + } + + /* Complain if the definition comes from a + discarded section. */ + if ((sec = *ps) != NULL && elf_discarded_section (sec)) + { + BFD_ASSERT (r_symndx != 0); + if (action & COMPLAIN) + (*finfo->info->callbacks->einfo) + (_("%X`%s' referenced in section `%A' of %B: " + "defined in discarded section `%A' of %B\n"), + sym_name, o, input_bfd, sec, sec->owner); + + /* Try to do the best we can to support buggy old + versions of gcc. Pretend that the symbol is + really defined in the kept linkonce section. + FIXME: This is quite broken. Modifying the + symbol here means we will be changing all later + uses of the symbol, not just in this section. */ + if (action & PRETEND) + { + asection *kept; + + kept = _bfd_elf_check_kept_section (sec); + if (kept != NULL) + { + *ps = kept; + continue; + } + } + + /* Remove the symbol reference from the reloc, but + don't kill the reloc completely. This is so that + a zero value will be written into the section, + which may have non-zero contents put there by the + assembler. Zero in things like an eh_frame fde + pc_begin allows stack unwinders to recognize the + fde as bogus. */ + rel->r_info &= r_type_mask; + rel->r_addend = 0; + } + } + } + + /* 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 relocatable 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 relocatable 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; + struct elf_link_hash_entry **rel_hash_list; + Elf_Internal_Shdr *input_rel_hdr, *input_rel_hdr2; + unsigned int next_erel; + bfd_boolean rela_normal; + + input_rel_hdr = &elf_section_data (o)->rel_hdr; + rela_normal = (bed->rela_normal + && (input_rel_hdr->sh_entsize + == bed->s->sizeof_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); + rel_hash_list = rel_hash; + last_offset = o->output_offset; + if (!finfo->info->relocatable) + 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->relocatable) + irela->r_offset += o->output_section->vma; + + last_offset = irela->r_offset; + + r_symndx = irela->r_info >> r_sym_shift; + 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 bfd_elf_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. */ + r_symndx = 0; + if (bfd_is_abs_section (sec)) + ; + else if (sec == NULL || sec->owner == NULL) + { + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + else + { + asection *osec = sec->output_section; + + /* If we have discarded a section, the output + section will be the absolute section. In + case of discarded link-once and discarded + SEC_MERGE sections, use the kept section. */ + if (bfd_is_abs_section (osec) + && sec->kept_section != NULL + && sec->kept_section->output_section != NULL) + { + osec = sec->kept_section->output_section; + irela->r_addend -= osec->vma; + } + + if (!bfd_is_abs_section (osec)) + { + r_symndx = osec->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->relocatable) + { + 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 (elf_hash_table (finfo->info) + ->tls_sec != NULL); + sym.st_value -= (elf_hash_table (finfo->info) + ->tls_sec->vma); + } + } + + finfo->indices[r_symndx] + = bfd_get_symcount (output_bfd); + + if (! elf_link_output_sym (finfo, name, &sym, sec, + NULL)) + return FALSE; + } + + r_symndx = finfo->indices[r_symndx]; + } + + irela->r_info = ((bfd_vma) r_symndx << r_sym_shift + | (irela->r_info & r_type_mask)); + } + + /* Swap out the relocs. */ + if (input_rel_hdr->sh_size != 0 + && !bed->elf_backend_emit_relocs (output_bfd, o, + input_rel_hdr, + internal_relocs, + rel_hash_list)) + 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); + rel_hash_list += NUM_SHDR_ENTRIES (input_rel_hdr); + if (!bed->elf_backend_emit_relocs (output_bfd, o, + input_rel_hdr2, + internal_relocs, + rel_hash_list)) + 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: + { + if (! (o->flags & SEC_EXCLUDE) + && ! bfd_set_section_contents (output_bfd, o->output_section, + contents, + (file_ptr) o->output_offset, + o->size)) + return FALSE; + } + break; + } + } + + return TRUE; +} + +/* Generate a reloc when linking an ELF file. This is a reloc + requested by the linker, and does not 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 (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; + const 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, NULL, NULL, 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_zmalloc (size); + if (buf == NULL) + return FALSE; + rstat = _bfd_relocate_contents (howto, output_bfd, 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, NULL, sym_name, howto->name, addend, NULL, + NULL, (bfd_vma) 0))) + { + free (buf); + return FALSE; + } + break; + } + ok = bfd_set_section_contents (output_bfd, output_section, buf, + link_order->offset, size); + free (buf); + if (! ok) + return FALSE; + } + + /* The address of a reloc is relative to the section in a + relocatable file, and is a virtual address in an executable + file. */ + offset = link_order->offset; + if (! info->relocatable) + 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; + } + if (bed->s->arch_size == 32) + irel[0].r_info = ELF32_R_INFO (indx, howto->type); + else + irel[0].r_info = ELF64_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 + * bed->s->sizeof_rel); + (*bed->s->swap_reloc_out) (output_bfd, irel, erel); + } + else + { + irel[0].r_addend = addend; + erel += (elf_section_data (output_section)->rel_count + * bed->s->sizeof_rela); + (*bed->s->swap_reloca_out) (output_bfd, irel, erel); + } + + ++elf_section_data (output_section)->rel_count; + + return TRUE; +} + + +/* Get the output vma of the section pointed to by the sh_link field. */ + +static bfd_vma +elf_get_linked_section_vma (struct bfd_link_order *p) +{ + Elf_Internal_Shdr **elf_shdrp; + asection *s; + int elfsec; + + s = p->u.indirect.section; + elf_shdrp = elf_elfsections (s->owner); + elfsec = _bfd_elf_section_from_bfd_section (s->owner, s); + elfsec = elf_shdrp[elfsec]->sh_link; + /* PR 290: + The Intel C compiler generates SHT_IA_64_UNWIND with + SHF_LINK_ORDER. But it doesn't set the sh_link or + sh_info fields. Hence we could get the situation + where elfsec is 0. */ + if (elfsec == 0) + { + const struct elf_backend_data *bed + = get_elf_backend_data (s->owner); + if (bed->link_order_error_handler) + bed->link_order_error_handler + (_("%B: warning: sh_link not set for section `%A'"), s->owner, s); + return 0; + } + else + { + s = elf_shdrp[elfsec]->bfd_section; + return s->output_section->vma + s->output_offset; + } +} + + +/* Compare two sections based on the locations of the sections they are + linked to. Used by elf_fixup_link_order. */ + +static int +compare_link_order (const void * a, const void * b) +{ + bfd_vma apos; + bfd_vma bpos; + + apos = elf_get_linked_section_vma (*(struct bfd_link_order **)a); + bpos = elf_get_linked_section_vma (*(struct bfd_link_order **)b); + if (apos < bpos) + return -1; + return apos > bpos; +} + + +/* Looks for sections with SHF_LINK_ORDER set. Rearranges them into the same + order as their linked sections. Returns false if this could not be done + because an output section includes both ordered and unordered + sections. Ideally we'd do this in the linker proper. */ + +static bfd_boolean +elf_fixup_link_order (bfd *abfd, asection *o) +{ + int seen_linkorder; + int seen_other; + int n; + struct bfd_link_order *p; + bfd *sub; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + unsigned elfsec; + struct bfd_link_order **sections; + asection *s, *other_sec, *linkorder_sec; + bfd_vma offset; + + other_sec = NULL; + linkorder_sec = NULL; + seen_other = 0; + seen_linkorder = 0; + for (p = o->map_head.link_order; p != NULL; p = p->next) + { + if (p->type == bfd_indirect_link_order) + { + s = p->u.indirect.section; + sub = s->owner; + if (bfd_get_flavour (sub) == bfd_target_elf_flavour + && elf_elfheader (sub)->e_ident[EI_CLASS] == bed->s->elfclass + && (elfsec = _bfd_elf_section_from_bfd_section (sub, s)) + && elfsec < elf_numsections (sub) + && elf_elfsections (sub)[elfsec]->sh_flags & SHF_LINK_ORDER) + { + seen_linkorder++; + linkorder_sec = s; + } + else + { + seen_other++; + other_sec = s; + } + } + else + seen_other++; + + if (seen_other && seen_linkorder) + { + if (other_sec && linkorder_sec) + (*_bfd_error_handler) (_("%A has both ordered [`%A' in %B] and unordered [`%A' in %B] sections"), + o, linkorder_sec, + linkorder_sec->owner, other_sec, + other_sec->owner); + else + (*_bfd_error_handler) (_("%A has both ordered and unordered sections"), + o); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + } + + if (!seen_linkorder) + return TRUE; + + sections = (struct bfd_link_order **) + xmalloc (seen_linkorder * sizeof (struct bfd_link_order *)); + seen_linkorder = 0; + + for (p = o->map_head.link_order; p != NULL; p = p->next) + { + sections[seen_linkorder++] = p; + } + /* Sort the input sections in the order of their linked section. */ + qsort (sections, seen_linkorder, sizeof (struct bfd_link_order *), + compare_link_order); + + /* Change the offsets of the sections. */ + offset = 0; + for (n = 0; n < seen_linkorder; n++) + { + s = sections[n]->u.indirect.section; + offset &= ~(bfd_vma)((1 << s->alignment_power) - 1); + s->output_offset = offset; + sections[n]->offset = offset; + offset += sections[n]->size; + } + + return TRUE; +} + + +/* Do the final step of an ELF link. */ + +bfd_boolean +bfd_elf_final_link (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; + const 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->hash)) + 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->relocatable + || info->emitrelocations); + + finfo.info = info; + finfo.output_bfd = abfd; + finfo.symstrtab = _bfd_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; + + /* 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 != NULL; o = o->next) + { + struct bfd_elf_section_data *esdo = elf_section_data (o); + o->reloc_count = 0; + + for (p = o->map_head.link_order; 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->relocatable || info->emitrelocations) + reloc_count = sec->reloc_count; + else if (bed->elf_backend_count_relocs) + { + Elf_Internal_Rela * relocs; + + relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, + info->keep_memory); + + reloc_count = (*bed->elf_backend_count_relocs) (sec, relocs); + + if (elf_section_data (o)->relocs != relocs) + free (relocs); + } + + if (sec->rawsize > max_contents_size) + max_contents_size = sec->rawsize; + if (sec->size > max_contents_size) + max_contents_size = sec->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 + / bed->s->sizeof_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 == bed->s->sizeof_rel + || entsize1 == bed->s->sizeof_rela); + same_size = !o->use_rela_p == (entsize1 == bed->s->sizeof_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 == bed->s->sizeof_rel + || entsize2 == bed->s->sizeof_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->relocatable && merged) + elf_link_hash_traverse (elf_hash_table (info), + _bfd_elf_link_sec_merge_syms, 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; + + /* Set sizes, and assign file positions for reloc sections. */ + for (o = abfd->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_RELOC) != 0) + { + if (!(_bfd_elf_link_size_reloc_section + (abfd, &elf_section_data (o)->rel_hdr, o))) + goto error_return; + + if (elf_section_data (o)->rel_hdr2 + && !(_bfd_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 = bed->s->sizeof_sym; + /* sh_link is set in assign_section_numbers. */ + /* sh_info is set below. */ + /* sh_offset is set just below. */ + symtab_hdr->sh_addralign = 1 << bed->s->log_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 *= bed->s->sizeof_sym; + finfo.symbuf = 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 = 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, NULL, &elfsym, bfd_und_section_ptr, + NULL)) + goto error_return; + } + + /* Output a symbol for each section. We output these even if we are + discarding local symbols, since they are used for relocs. These + symbols have no names. We store the index of each one in the + index field of the section, so that we can find it again when + outputting relocs. */ + if (info->strip != strip_all + || emit_relocs) + { + 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 = bfd_section_from_elf_index (abfd, i); + if (o != NULL) + o->target_index = bfd_get_symcount (abfd); + elfsym.st_shndx = i; + if (info->relocatable || o == NULL) + elfsym.st_value = 0; + else + elfsym.st_value = o->vma; + if (! elf_link_output_sym (&finfo, NULL, &elfsym, o, NULL)) + 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_malloc (max_contents_size); + if (finfo.contents == NULL) + goto error_return; + } + + if (max_external_reloc_size != 0) + { + finfo.external_relocs = 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 = bfd_malloc (amt); + if (finfo.internal_relocs == NULL) + goto error_return; + } + + if (max_sym_count != 0) + { + amt = max_sym_count * bed->s->sizeof_sym; + finfo.external_syms = bfd_malloc (amt); + if (finfo.external_syms == NULL) + goto error_return; + + amt = max_sym_count * sizeof (Elf_Internal_Sym); + finfo.internal_syms = bfd_malloc (amt); + if (finfo.internal_syms == NULL) + goto error_return; + + amt = max_sym_count * sizeof (long); + finfo.indices = bfd_malloc (amt); + if (finfo.indices == NULL) + goto error_return; + + amt = max_sym_count * sizeof (asection *); + finfo.sections = 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 = bfd_malloc (amt); + if (finfo.locsym_shndx == NULL) + goto error_return; + } + + if (elf_hash_table (info)->tls_sec) + { + bfd_vma base, end = 0; + asection *sec; + + for (sec = elf_hash_table (info)->tls_sec; + sec && (sec->flags & SEC_THREAD_LOCAL); + sec = sec->next) + { + bfd_size_type size = sec->size; + + if (size == 0 + && (sec->flags & SEC_HAS_CONTENTS) == 0) + { + struct bfd_link_order *o = sec->map_tail.link_order; + if (o != NULL) + size = o->offset + o->size; + } + end = sec->vma + size; + } + base = elf_hash_table (info)->tls_sec->vma; + end = align_power (end, elf_hash_table (info)->tls_sec->alignment_power); + elf_hash_table (info)->tls_size = end - base; + } + + /* Reorder SHF_LINK_ORDER sections. */ + for (o = abfd->sections; o != NULL; o = o->next) + { + if (!elf_fixup_link_order (abfd, o)) + return FALSE; + } + + /* Since ELF permits relocations to be against local symbols, we + must have the local symbols available when we do the relocations. + Since we would rather only read the local symbols once, and we + 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 relocatable 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 relocatable + 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->map_head.link_order; 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, + &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; + bfd_byte *dynsym = finfo.dynsym_sec->contents; + long last_local = 0; + + /* Write out the section symbols for the output sections. */ + if (info->shared || elf_hash_table (info)->is_relocatable_executable) + { + 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; + bfd_byte *dest; + long dynindx; + + dynindx = elf_section_data (s)->dynindx; + if (dynindx <= 0) + continue; + indx = elf_section_data (s)->this_idx; + BFD_ASSERT (indx > 0); + sym.st_shndx = indx; + if (! check_dynsym (abfd, &sym)) + return FALSE; + sym.st_value = s->vma; + dest = dynsym + dynindx * bed->s->sizeof_sym; + if (last_local < dynindx) + last_local = dynindx; + bed->s->swap_symbol_out (abfd, &sym, dest, 0); + } + } + + /* 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; + bfd_byte *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; + if (! check_dynsym (abfd, &sym)) + return FALSE; + 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 * bed->s->sizeof_sym; + bed->s->swap_symbol_out (abfd, &sym, dest, 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, + &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) + (void *, const char *, Elf_Internal_Sym *, asection *, + struct elf_link_hash_entry *); + + if (! ((*bed->elf_backend_output_arch_syms) + (abfd, info, &finfo, (out_sym_func) elf_link_output_sym))) + return FALSE; + } + + /* Flush all symbols to the file. */ + if (! elf_link_flush_output_syms (&finfo, bed)) + 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 (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) + { + bfd_byte *dyncon, *dynconend; + + /* Fix up .dynamic entries. */ + o = bfd_get_section_by_name (dynobj, ".dynamic"); + BFD_ASSERT (o != NULL); + + dyncon = o->contents; + dynconend = o->contents + o->size; + for (; dyncon < dynconend; dyncon += bed->s->sizeof_dyn) + { + Elf_Internal_Dyn dyn; + const char *name; + unsigned int type; + + bed->s->swap_dyn_in (dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + default: + continue; + case DT_NULL: + if (relativecount > 0 && dyncon + bed->s->sizeof_dyn < 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: continue; + } + dyn.d_un.d_val = relativecount; + relativecount = 0; + break; + } + continue; + + 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; + } + break; + } + } + continue; + + 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) + (_("%B: could not find output section %s"), abfd, name); + goto error_return; + } + if (o->size == 0) + (*_bfd_error_handler) + (_("warning: %s section has zero size"), name); + dyn.d_un.d_val = o->size; + 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) + (_("%B: could not find output section %s"), abfd, name); + goto error_return; + } + dyn.d_un.d_ptr = o->vma; + 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; + } + } + } + break; + } + bed->s->swap_dyn_out (dynobj, &dyn, dyncon); + } + } + + /* 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; + + /* Check for DT_TEXTREL (late, in case the backend removes it). */ + if (info->warn_shared_textrel && info->shared) + { + bfd_byte *dyncon, *dynconend; + + /* Fix up .dynamic entries. */ + o = bfd_get_section_by_name (dynobj, ".dynamic"); + BFD_ASSERT (o != NULL); + + dyncon = o->contents; + dynconend = o->contents + o->size; + for (; dyncon < dynconend; dyncon += bed->s->sizeof_dyn) + { + Elf_Internal_Dyn dyn; + + bed->s->swap_dyn_in (dynobj, dyncon, &dyn); + + if (dyn.d_tag == DT_TEXTREL) + { + _bfd_error_handler + (_("warning: creating a DT_TEXTREL in a shared object.")); + break; + } + } + } + + for (o = dynobj->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_HAS_CONTENTS) == 0 + || o->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 _bfd_elf_link_create_dynamic_sections. */ + continue; + } + if (elf_hash_table (info)->stab_info.stabstr == o) + continue; + if (elf_hash_table (info)->eh_info.hdr_sec == o) + 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->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->relocatable) + { + 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.stabstr != 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; +} + +/* Garbage collect unused sections. */ + +/* 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) + (asection *, struct bfd_link_info *, Elf_Internal_Rela *, + struct elf_link_hash_entry *, Elf_Internal_Sym *); + +bfd_boolean +_bfd_elf_gc_mark (struct bfd_link_info *info, + asection *sec, + gc_mark_hook_fn gc_mark_hook) +{ + bfd_boolean ret; + bfd_boolean is_eh; + 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 (!_bfd_elf_gc_mark (info, group_sec, gc_mark_hook)) + return FALSE; + + /* Look through the section relocs. */ + ret = TRUE; + is_eh = strcmp (sec->name, ".eh_frame") == 0; + 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; + const struct elf_backend_data *bed = get_elf_backend_data (input_bfd); + Elf_Internal_Sym *isym = NULL; + int r_sym_shift; + + 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 / bed->s->sizeof_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 = _bfd_elf_link_read_relocs (input_bfd, sec, NULL, NULL, + info->keep_memory); + if (relstart == NULL) + { + ret = FALSE; + goto out1; + } + relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel; + + if (bed->s->arch_size == 32) + r_sym_shift = 8; + else + r_sym_shift = 32; + + for (rel = relstart; rel < relend; rel++) + { + unsigned long r_symndx; + asection *rsec; + struct elf_link_hash_entry *h; + + r_symndx = rel->r_info >> r_sym_shift; + 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]; + 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; + 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 (is_eh) + rsec->gc_mark_from_eh = 1; + else if (!_bfd_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; +} + +/* Sweep symbols in swept sections. Called via elf_link_hash_traverse. */ + +struct elf_gc_sweep_symbol_info { + struct bfd_link_info *info; + void (*hide_symbol) (struct bfd_link_info *, struct elf_link_hash_entry *, + bfd_boolean); +}; + +static bfd_boolean +elf_gc_sweep_symbol (struct elf_link_hash_entry *h, void *data) +{ + 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) + && !h->root.u.def.section->gc_mark + && !(h->root.u.def.section->owner->flags & DYNAMIC)) + { + struct elf_gc_sweep_symbol_info *inf = data; + (*inf->hide_symbol) (inf->info, h, TRUE); + } + + return TRUE; +} + +/* The sweep phase of garbage collection. Remove all garbage sections. */ + +typedef bfd_boolean (*gc_sweep_hook_fn) + (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *); + +static bfd_boolean +elf_gc_sweep (bfd *abfd, struct bfd_link_info *info) +{ + bfd *sub; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + gc_sweep_hook_fn gc_sweep_hook = bed->gc_sweep_hook; + unsigned long section_sym_count; + struct elf_gc_sweep_symbol_info sweep_info; + + 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 debug and special sections. */ + if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0 + || (o->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0) + o->gc_mark = 1; + + 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) != 0 + && o->reloc_count > 0 + && !bfd_is_abs_section (o->output_section)) + { + Elf_Internal_Rela *internal_relocs; + bfd_boolean r; + + internal_relocs + = _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? */ + sweep_info.info = info; + sweep_info.hide_symbol = bed->elf_backend_hide_symbol; + elf_link_hash_traverse (elf_hash_table (info), elf_gc_sweep_symbol, + &sweep_info); + + _bfd_elf_link_renumber_dynsyms (abfd, info, §ion_sym_count); + return TRUE; +} + +/* Propagate collected vtable information. This is called through + elf_link_hash_traverse. */ + +static bfd_boolean +elf_gc_propagate_vtable_entries_used (struct elf_link_hash_entry *h, void *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 == NULL || 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->used && h->vtable->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->used == NULL) + { + /* None of this table's entries were referenced. Re-use the + parent's table. */ + h->vtable->used = h->vtable->parent->vtable->used; + h->vtable->size = h->vtable->parent->vtable->size; + } + else + { + size_t n; + bfd_boolean *cu, *pu; + + /* Or the parent's entries into ours. */ + cu = h->vtable->used; + cu[-1] = TRUE; + pu = h->vtable->parent->vtable->used; + if (pu != NULL) + { + const struct elf_backend_data *bed; + unsigned int log_file_align; + + bed = get_elf_backend_data (h->root.u.def.section->owner); + log_file_align = bed->s->log_file_align; + n = h->vtable->parent->vtable->size >> log_file_align; + while (n--) + { + if (*pu) + *cu = TRUE; + pu++; + cu++; + } + } + } + + return TRUE; +} + +static bfd_boolean +elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h, void *okp) +{ + asection *sec; + bfd_vma hstart, hend; + Elf_Internal_Rela *relstart, *relend, *rel; + const struct elf_backend_data *bed; + unsigned int log_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 == NULL || 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 = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL, TRUE); + if (!relstart) + return *(bfd_boolean *) okp = FALSE; + bed = get_elf_backend_data (sec->owner); + log_file_align = bed->s->log_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->used + && (rel->r_offset - hstart) < h->vtable->size) + { + bfd_vma entry = (rel->r_offset - hstart) >> log_file_align; + if (h->vtable->used[entry]) + continue; + } + /* Otherwise, kill it. */ + rel->r_offset = rel->r_info = rel->r_addend = 0; + } + + return TRUE; +} + +/* Mark sections containing dynamically referenced symbols. When + building shared libraries, we must assume that any visible symbol is + referenced. */ + +bfd_boolean +bfd_elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, void *inf) +{ + struct bfd_link_info *info = (struct bfd_link_info *) inf; + + 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) + && (h->ref_dynamic + || (!info->executable + && h->def_regular + && ELF_ST_VISIBILITY (h->other) != STV_INTERNAL + && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN))) + h->root.u.def.section->flags |= SEC_KEEP; + + return TRUE; +} + +/* Do mark and sweep of unused sections. */ + +bfd_boolean +bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info) +{ + bfd_boolean ok = TRUE; + bfd *sub; + asection * (*gc_mark_hook) + (asection *, struct bfd_link_info *, Elf_Internal_Rela *, + struct elf_link_hash_entry *h, Elf_Internal_Sym *); + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + + if (!bed->can_gc_sections + || info->relocatable + || info->emitrelocations + || !is_elf_hash_table (info->hash)) + { + (*_bfd_error_handler)(_("Warning: gc-sections option ignored")); + 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, + &ok); + if (!ok) + return FALSE; + + /* Kill the vtable relocations that were not used. */ + elf_link_hash_traverse (elf_hash_table (info), + elf_gc_smash_unused_vtentry_relocs, + &ok); + if (!ok) + return FALSE; + + /* Mark dynamically referenced symbols. */ + if (elf_hash_table (info)->dynamic_sections_created) + elf_link_hash_traverse (elf_hash_table (info), + bed->gc_mark_dynamic_ref, + info); + + /* Grovel through relocs to find out who stays ... */ + gc_mark_hook = bed->gc_mark_hook; + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + 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) != 0 && !o->gc_mark) + if (!_bfd_elf_gc_mark (info, o, gc_mark_hook)) + return FALSE; + } + + /* ... again for sections marked from eh_frame. */ + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + asection *o; + + if (bfd_get_flavour (sub) != bfd_target_elf_flavour) + continue; + + /* Keep .gcc_except_table.* if the associated .text.* is + marked. This isn't very nice, but the proper solution, + splitting .eh_frame up and using comdat doesn't pan out + easily due to needing special relocs to handle the + difference of two symbols in separate sections. + Don't keep code sections referenced by .eh_frame. */ + for (o = sub->sections; o != NULL; o = o->next) + if (!o->gc_mark && o->gc_mark_from_eh && (o->flags & SEC_CODE) == 0) + { + if (strncmp (o->name, ".gcc_except_table.", 18) == 0) + { + unsigned long len; + char *fn_name; + asection *fn_text; + + len = strlen (o->name + 18) + 1; + fn_name = bfd_malloc (len + 6); + if (fn_name == NULL) + return FALSE; + memcpy (fn_name, ".text.", 6); + memcpy (fn_name + 6, o->name + 18, len); + fn_text = bfd_get_section_by_name (sub, fn_name); + free (fn_name); + if (fn_text == NULL || !fn_text->gc_mark) + continue; + } + + /* If not using specially named exception table section, + then keep whatever we are using. */ + if (!_bfd_elf_gc_mark (info, o, gc_mark_hook)) + return FALSE; + } + } + + /* ... and mark SEC_EXCLUDE for those that go. */ + return elf_gc_sweep (abfd, info); +} + +/* Called from check_relocs to record the existence of a VTINHERIT reloc. */ + +bfd_boolean +bfd_elf_gc_record_vtinherit (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; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + + /* 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 / bed->s->sizeof_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) ("%B: %A+%lu: No symbol found for INHERIT", + abfd, sec, (unsigned long) offset); + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + + win: + if (!child->vtable) + { + child->vtable = bfd_zalloc (abfd, sizeof (*child->vtable)); + if (!child->vtable) + return FALSE; + } + 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 existence of a VTENTRY reloc. */ + +bfd_boolean +bfd_elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec ATTRIBUTE_UNUSED, + struct elf_link_hash_entry *h, + bfd_vma addend) +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + unsigned int log_file_align = bed->s->log_file_align; + + if (!h->vtable) + { + h->vtable = bfd_zalloc (abfd, sizeof (*h->vtable)); + if (!h->vtable) + return FALSE; + } + + if (addend >= h->vtable->size) + { + size_t size, bytes, file_align; + bfd_boolean *ptr = h->vtable->used; + + /* While the symbol is undefined, we have to be prepared to handle + a zero size. */ + file_align = 1 << log_file_align; + if (h->root.type == bfd_link_hash_undefined) + size = addend + file_align; + else + { + size = h->size; + if (addend >= size) + { + /* Oops! We've got a reference past the defined end of + the table. This is probably a bug -- shall we warn? */ + size = addend + file_align; + } + } + size = (size + file_align - 1) & -file_align; + + /* Allocate one extra entry for use as a "done" flag for the + consolidation pass. */ + bytes = ((size >> log_file_align) + 1) * sizeof (bfd_boolean); + + if (ptr) + { + ptr = bfd_realloc (ptr - 1, bytes); + + if (ptr != NULL) + { + size_t oldbytes; + + oldbytes = (((h->vtable->size >> log_file_align) + 1) + * sizeof (bfd_boolean)); + memset (((char *) ptr) + oldbytes, 0, bytes - oldbytes); + } + } + else + ptr = bfd_zmalloc (bytes); + + if (ptr == NULL) + return FALSE; + + /* And arrange for that done flag to be at index -1. */ + h->vtable->used = ptr + 1; + h->vtable->size = size; + } + + h->vtable->used[addend >> log_file_align] = TRUE; + + return TRUE; +} + +struct alloc_got_off_arg { + bfd_vma gotoff; + unsigned int got_elt_size; +}; + +/* 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 (struct elf_link_hash_entry *h, void *arg) +{ + struct alloc_got_off_arg *gofarg = arg; + + 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 = gofarg->gotoff; + gofarg->gotoff += gofarg->got_elt_size; + } + else + h->got.offset = (bfd_vma) -1; + + 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 +bfd_elf_gc_common_finalize_got_offsets (bfd *abfd, + struct bfd_link_info *info) +{ + bfd *i; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + bfd_vma gotoff; + unsigned int got_elt_size = bed->s->arch_size / 8; + struct alloc_got_off_arg gofarg; + + if (! is_elf_hash_table (info->hash)) + return FALSE; + + /* 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 / bed->s->sizeof_sym; + else + locsymcount = symtab_hdr->sh_info; + + for (j = 0; j < locsymcount; ++j) + { + if (local_got[j] > 0) + { + local_got[j] = gotoff; + gotoff += got_elt_size; + } + else + local_got[j] = (bfd_vma) -1; + } + } + + /* Then the global .got entries. .plt refcounts are handled by + adjust_dynamic_symbol */ + gofarg.gotoff = gotoff; + gofarg.got_elt_size = got_elt_size; + elf_link_hash_traverse (elf_hash_table (info), + elf_gc_allocate_got_offsets, + &gofarg); + return TRUE; +} + +/* Many folk need no more in the way of final link than this, once + got entry reference counting is enabled. */ + +bfd_boolean +bfd_elf_gc_common_final_link (bfd *abfd, struct bfd_link_info *info) +{ + if (!bfd_elf_gc_common_finalize_got_offsets (abfd, info)) + return FALSE; + + /* Invoke the regular ELF backend linker to do all the work. */ + return bfd_elf_final_link (abfd, info); +} + +bfd_boolean +bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie) +{ + struct elf_reloc_cookie *rcookie = 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 = rcookie->rel->r_info >> rcookie->r_sym_shift; + 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 = bfd_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 +bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info) +{ + struct elf_reloc_cookie cookie; + asection *stab, *eh; + Elf_Internal_Shdr *symtab_hdr; + const struct elf_backend_data *bed; + bfd *abfd; + unsigned int count; + bfd_boolean ret = FALSE; + + if (info->traditional_format + || !is_elf_hash_table (info->hash)) + 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->relocatable + || (eh != NULL + && (eh->size == 0 + || bfd_is_abs_section (eh->output_section)))) + eh = NULL; + + stab = bfd_get_section_by_name (abfd, ".stab"); + if (stab != NULL + && (stab->size == 0 + || bfd_is_abs_section (stab->output_section) + || stab->sec_info_type != 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 / bed->s->sizeof_sym; + cookie.extsymoff = 0; + } + else + { + cookie.locsymcount = symtab_hdr->sh_info; + cookie.extsymoff = symtab_hdr->sh_info; + } + + if (bed->s->arch_size == 32) + cookie.r_sym_shift = 8; + else + cookie.r_sym_shift = 32; + + 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 = _bfd_elf_link_read_relocs (abfd, stab, NULL, 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, + bfd_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 = _bfd_elf_link_read_relocs (abfd, eh, NULL, 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, + bfd_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->relocatable + && _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info)) + ret = TRUE; + + return ret; +} + +void +_bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec) +{ + flagword flags; + const char *name, *p; + struct bfd_section_already_linked *l; + struct bfd_section_already_linked_hash_entry *already_linked_list; + asection *group; + + /* A single member comdat group section may be discarded by a + linkonce section. See below. */ + if (sec->output_section == bfd_abs_section_ptr) + return; + + flags = sec->flags; + + /* Check if it belongs to a section group. */ + group = elf_sec_group (sec); + + /* Return if it isn't a linkonce section nor a member of a group. A + comdat group section also has SEC_LINK_ONCE set. */ + if ((flags & SEC_LINK_ONCE) == 0 && group == NULL) + return; + + if (group) + { + /* If this is the member of a single member comdat group, check if + the group should be discarded. */ + if (elf_next_in_group (sec) == sec + && (group->flags & SEC_LINK_ONCE) != 0) + sec = group; + else + 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); + + if (strncmp (name, ".gnu.linkonce.", sizeof (".gnu.linkonce.") - 1) == 0 + && (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL) + p++; + else + p = name; + + already_linked_list = bfd_section_already_linked_table_lookup (p); + + for (l = already_linked_list->entry; l != NULL; l = l->next) + { + /* We may have 3 different sections on the list: group section, + comdat section and linkonce section. SEC may be a linkonce or + group section. We match a group section with a group section, + a linkonce section with a linkonce section, and ignore comdat + section. */ + if ((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP) + && strcmp (name, l->sec->name) == 0 + && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL) + { + /* 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: + (*_bfd_error_handler) + (_("%B: ignoring duplicate section `%A'"), + abfd, sec); + break; + + case SEC_LINK_DUPLICATES_SAME_SIZE: + if (sec->size != l->sec->size) + (*_bfd_error_handler) + (_("%B: duplicate section `%A' has different size"), + abfd, sec); + break; + + case SEC_LINK_DUPLICATES_SAME_CONTENTS: + if (sec->size != l->sec->size) + (*_bfd_error_handler) + (_("%B: duplicate section `%A' has different size"), + abfd, sec); + else if (sec->size != 0) + { + bfd_byte *sec_contents, *l_sec_contents; + + if (!bfd_malloc_and_get_section (abfd, sec, &sec_contents)) + (*_bfd_error_handler) + (_("%B: warning: could not read contents of section `%A'"), + abfd, sec); + else if (!bfd_malloc_and_get_section (l->sec->owner, l->sec, + &l_sec_contents)) + (*_bfd_error_handler) + (_("%B: warning: could not read contents of section `%A'"), + l->sec->owner, l->sec); + else if (memcmp (sec_contents, l_sec_contents, sec->size) != 0) + (*_bfd_error_handler) + (_("%B: warning: duplicate section `%A' has different contents"), + abfd, sec); + + if (sec_contents) + free (sec_contents); + if (l_sec_contents) + free (l_sec_contents); + } + break; + } + + /* Set the output_section field so that lang_add_section + does not create a lang_input_section structure for this + section. Since there might be a symbol in the section + being discarded, we must retain a pointer to the section + which we are really going to use. */ + sec->output_section = bfd_abs_section_ptr; + sec->kept_section = l->sec; + + if (flags & SEC_GROUP) + { + asection *first = elf_next_in_group (sec); + asection *s = first; + + while (s != NULL) + { + s->output_section = bfd_abs_section_ptr; + /* Record which group discards it. */ + s->kept_section = l->sec; + s = elf_next_in_group (s); + /* These lists are circular. */ + if (s == first) + break; + } + } + + return; + } + } + + if (group) + { + /* If this is the member of a single member comdat group and the + group hasn't be discarded, we check if it matches a linkonce + section. We only record the discarded comdat group. Otherwise + the undiscarded group will be discarded incorrectly later since + itself has been recorded. */ + for (l = already_linked_list->entry; l != NULL; l = l->next) + if ((l->sec->flags & SEC_GROUP) == 0 + && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL + && bfd_elf_match_symbols_in_sections (l->sec, + elf_next_in_group (sec))) + { + elf_next_in_group (sec)->output_section = bfd_abs_section_ptr; + elf_next_in_group (sec)->kept_section = l->sec; + group->output_section = bfd_abs_section_ptr; + break; + } + if (l == NULL) + return; + } + else + /* There is no direct match. But for linkonce section, we should + check if there is a match with comdat group member. We always + record the linkonce section, discarded or not. */ + for (l = already_linked_list->entry; l != NULL; l = l->next) + if (l->sec->flags & SEC_GROUP) + { + asection *first = elf_next_in_group (l->sec); + + if (first != NULL + && elf_next_in_group (first) == first + && bfd_elf_match_symbols_in_sections (first, sec)) + { + sec->output_section = bfd_abs_section_ptr; + sec->kept_section = l->sec; + break; + } + } + + /* This is the first section with this name. Record it. */ + bfd_section_already_linked_table_insert (already_linked_list, sec); +} + +bfd_boolean +_bfd_elf_common_definition (Elf_Internal_Sym *sym) +{ + return sym->st_shndx == SHN_COMMON; +} + +unsigned int +_bfd_elf_common_section_index (asection *sec ATTRIBUTE_UNUSED) +{ + return SHN_COMMON; +} + +asection * +_bfd_elf_common_section (asection *sec ATTRIBUTE_UNUSED) +{ + return bfd_com_section_ptr; +} diff --git a/contrib/binutils-2.17/bfd/elfxx-target.h b/contrib/binutils-2.17/bfd/elfxx-target.h new file mode 100644 index 0000000000..503726d2b8 --- /dev/null +++ b/contrib/binutils-2.17/bfd/elfxx-target.h @@ -0,0 +1,853 @@ +/* Target definitions for NN-bit ELF + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + 2003, 2004, 2005, 2006 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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. */ + +#ifndef bfd_elfNN_close_and_cleanup +#define bfd_elfNN_close_and_cleanup _bfd_elf_close_and_cleanup +#endif +#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_get_synthetic_symtab +#define bfd_elfNN_get_synthetic_symtab \ + _bfd_elf_get_synthetic_symtab +#endif +#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 +#ifndef bfd_elfNN_find_inliner_info +#define bfd_elfNN_find_inliner_info _bfd_elf_find_inliner_info +#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_canonicalize_symtab _bfd_elf_canonicalize_symtab +#define bfd_elfNN_get_symtab_upper_bound _bfd_elf_get_symtab_upper_bound +#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_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 (*) (bfd*, struct bfd_section *)) 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_dynamic_ref +#define elf_backend_gc_mark_dynamic_ref bfd_elf_gc_mark_dynamic_ref_symbol +#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_elf_gc_sections +#endif + +#ifndef bfd_elfNN_bfd_merge_sections +#define bfd_elfNN_bfd_merge_sections \ + _bfd_elf_merge_sections +#endif + +#ifndef bfd_elfNN_bfd_is_group_section +#define bfd_elfNN_bfd_is_group_section bfd_elf_is_group_section +#endif + +#ifndef bfd_elfNN_bfd_discard_group +#define bfd_elfNN_bfd_discard_group bfd_generic_discard_group +#endif + +#ifndef bfd_elfNN_section_already_linked +#define bfd_elfNN_section_already_linked \ + _bfd_elf_section_already_linked +#endif + +#ifndef bfd_elfNN_bfd_make_debug_symbol +#define bfd_elfNN_bfd_make_debug_symbol \ + ((asymbol * (*) (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_header_data +#define bfd_elfNN_bfd_copy_private_header_data \ + _bfd_elf_copy_private_header_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 (*) (bfd *, bfd *)) bfd_true) +#endif +#ifndef bfd_elfNN_bfd_set_private_flags +#define bfd_elfNN_bfd_set_private_flags \ + ((bfd_boolean (*) (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_bfd_is_target_special_symbol +#define bfd_elfNN_bfd_is_target_special_symbol \ + ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) +#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 +#ifndef bfd_elfNN_bfd_link_add_symbols +#define bfd_elfNN_bfd_link_add_symbols bfd_elf_link_add_symbols +#endif +#ifndef bfd_elfNN_bfd_final_link +#define bfd_elfNN_bfd_final_link bfd_elf_final_link +#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 bfd_elfNN_print_symbol +#define bfd_elfNN_print_symbol bfd_elf_print_symbol +#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_MINPAGESIZE +#define ELF_MINPAGESIZE ELF_MAXPAGESIZE +#endif + +#ifndef ELF_DYNAMIC_SEC_FLAGS +/* Note that we set the SEC_IN_MEMORY flag for these sections. */ +#define ELF_DYNAMIC_SEC_FLAGS \ + (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS \ + | SEC_IN_MEMORY | SEC_LINKER_CREATED) +#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_archive_symbol_lookup +#define elf_backend_archive_symbol_lookup _bfd_elf_archive_symbol_lookup +#endif +#ifndef elf_backend_name_local_section_symbols +#define elf_backend_name_local_section_symbols 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 _bfd_elf_make_section_from_shdr +#endif +#ifndef elf_backend_section_flags +#define elf_backend_section_flags 0 +#endif +#ifndef elf_backend_get_sec_type_attr +#define elf_backend_get_sec_type_attr _bfd_elf_get_sec_type_attr +#endif +#ifndef elf_backend_section_from_phdr +#define elf_backend_section_from_phdr _bfd_elf_make_section_from_phdr +#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_omit_section_dynsym +#define elf_backend_omit_section_dynsym _bfd_elf_link_omit_section_dynsym +#endif +#ifndef elf_backend_check_relocs +#define elf_backend_check_relocs 0 +#endif +#ifndef elf_backend_check_directives +#define elf_backend_check_directives 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_bfd_from_remote_memory +#define elf_backend_bfd_from_remote_memory _bfd_elfNN_bfd_from_remote_memory +#endif +#ifndef elf_backend_got_header_size +#define elf_backend_got_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_fixup_symbol +#define elf_backend_fixup_symbol NULL +#endif +#ifndef elf_backend_merge_symbol_attribute +#define elf_backend_merge_symbol_attribute NULL +#endif +#ifndef elf_backend_ignore_undef_symbol +#define elf_backend_ignore_undef_symbol NULL +#endif +#ifndef elf_backend_emit_relocs +#define elf_backend_emit_relocs _bfd_elf_link_output_relocs +#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_action_discarded +#define elf_backend_action_discarded _bfd_elf_default_action_discarded +#endif +#ifndef elf_backend_eh_frame_address_size +#define elf_backend_eh_frame_address_size _bfd_elf_eh_frame_address_size +#endif +#ifndef elf_backend_can_make_relative_eh_frame +#define elf_backend_can_make_relative_eh_frame _bfd_elf_can_make_relative +#endif +#ifndef elf_backend_can_make_lsda_relative_eh_frame +#define elf_backend_can_make_lsda_relative_eh_frame _bfd_elf_can_make_relative +#endif +#ifndef elf_backend_encode_eh_address +#define elf_backend_encode_eh_address _bfd_elf_encode_eh_address +#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_backend_plt_sym_val +#define elf_backend_plt_sym_val NULL +#endif +#ifndef elf_backend_relplt_name +#define elf_backend_relplt_name NULL +#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_special_sections +#define elf_backend_special_sections NULL +#endif + +#ifndef elf_backend_sign_extend_vma +#define elf_backend_sign_extend_vma 0 +#endif + +#ifndef elf_backend_link_order_error_handler +#define elf_backend_link_order_error_handler _bfd_default_error_handler +#endif + +#ifndef elf_backend_common_definition +#define elf_backend_common_definition _bfd_elf_common_definition +#endif + +#ifndef elf_backend_common_section_index +#define elf_backend_common_section_index _bfd_elf_common_section_index +#endif + +#ifndef elf_backend_common_section +#define elf_backend_common_section _bfd_elf_common_section +#endif + +#ifndef elf_backend_merge_symbol +#define elf_backend_merge_symbol NULL +#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_MINPAGESIZE, /* minpagesize */ + ELF_DYNAMIC_SEC_FLAGS, /* dynamic_sec_flags */ + 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_archive_symbol_lookup, + elf_backend_name_local_section_symbols, + elf_backend_section_processing, + elf_backend_section_from_shdr, + elf_backend_section_flags, + elf_backend_get_sec_type_attr, + 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_omit_section_dynsym, + elf_backend_check_relocs, + elf_backend_check_directives, + 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_dynamic_ref, + 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_fixup_symbol, + elf_backend_merge_symbol_attribute, + elf_backend_ignore_undef_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_action_discarded, + elf_backend_eh_frame_address_size, + elf_backend_can_make_relative_eh_frame, + elf_backend_can_make_lsda_relative_eh_frame, + elf_backend_encode_eh_address, + elf_backend_write_section, + elf_backend_mips_irix_compat, + elf_backend_mips_rtype_to_howto, + elf_backend_ecoff_debug_swap, + elf_backend_bfd_from_remote_memory, + elf_backend_plt_sym_val, + elf_backend_common_definition, + elf_backend_common_section_index, + elf_backend_common_section, + elf_backend_merge_symbol, + elf_backend_link_order_error_handler, + elf_backend_relplt_name, + ELF_MACHINE_ALT1, + ELF_MACHINE_ALT2, + &elf_backend_size_info, + elf_backend_special_sections, + elf_backend_got_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_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: */ + &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_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: */ + &elfNN_bed +}; +#endif diff --git a/contrib/binutils-2.17/bfd/format.c b/contrib/binutils-2.17/bfd/format.c new file mode 100644 index 0000000000..6a34dd2bea --- /dev/null +++ b/contrib/binutils-2.17/bfd/format.c @@ -0,0 +1,446 @@ +/* Generic BFD support for file formats. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1999, 2000, 2001, 2002, + 2003, 2005 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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. + +SUBSECTION + File format functions +*/ + +#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 (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 (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 = 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 (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 (matching_vector); + + /* If the file was opened for update, then `output_has_begun' + some time ago when the file was created. Do not recompute + sections sizes or alignments in _bfd_set_section_contents. + We can not set this flag until after checking the format, + because it will interfere with creation of BFD sections. */ + if (abfd->direction == both_direction) + abfd->output_has_begun = TRUE; + + 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 (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; + + /* Don't check the default target twice. */ + if (*target == &binary_vec + || (!abfd->target_defaulted && *target == save_targ)) + continue; + + abfd->xvec = *target; /* Change BFD's target temporarily. */ + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + { + if (matching) + free (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++; + } + 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 (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 (matching_vector); + + /* If the file was opened for update, then `output_has_begun' + some time ago when the file was created. Do not recompute + sections sizes or alignments in _bfd_set_section_contents. + We can not set this flag until after checking the format, + because it will interfere with creation of BFD sections. */ + if (abfd->direction == both_direction) + abfd->output_has_begun = TRUE; + + 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 (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 (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 (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/assembler/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.17/bfd/genlink.h b/contrib/binutils-2.17/bfd/genlink.h new file mode 100644 index 0000000000..175bee6877 --- /dev/null +++ b/contrib/binutils-2.17/bfd/genlink.h @@ -0,0 +1,109 @@ +/* genlink.h -- interface to the BFD generic linker + Copyright 1993, 1994, 1996, 2002, 2005 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 (*) (struct bfd_link_hash_entry *, void *)) (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 + (bfd *, bfd *, struct bfd_link_info *, size_t *); + +/* 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 + (struct generic_link_hash_entry *, void *); + +/* Generic link hash table entry creation routine. */ +struct bfd_hash_entry *_bfd_generic_link_hash_newfunc + (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); + +#endif diff --git a/contrib/binutils-2.17/bfd/hash.c b/contrib/binutils-2.17/bfd/hash.c new file mode 100644 index 0000000000..ce9ba5c629 --- /dev/null +++ b/contrib/binutils-2.17/bfd/hash.c @@ -0,0 +1,736 @@ +/* hash.c -- hash table routines for BFD + Copyright 1993, 1994, 1995, 1997, 1999, 2001, 2002, 2003, 2004, 2005, + 2006 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "objalloc.h" +#include "libiberty.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. + +@findex bfd_hash_set_default_size + Use <> to set the default size of + hash table to use. + +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} (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 == NULL) +. { +. ret = bfd_hash_allocate (table, sizeof (* ret)); +. if (ret == 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 +static size_t bfd_default_hash_table_size = DEFAULT_SIZE; + +/* Create a new hash table, given a number of entries. */ + +bfd_boolean +bfd_hash_table_init_n (struct bfd_hash_table *table, + struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int entsize, + unsigned int size) +{ + unsigned int alloc; + + alloc = size * sizeof (struct bfd_hash_entry *); + + table->memory = (void *) objalloc_create (); + if (table->memory == NULL) + { + bfd_set_error (bfd_error_no_memory); + return FALSE; + } + table->table = objalloc_alloc ((struct objalloc *) table->memory, alloc); + if (table->table == NULL) + { + bfd_set_error (bfd_error_no_memory); + return FALSE; + } + memset ((void *) table->table, 0, alloc); + table->size = size; + table->entsize = entsize; + table->newfunc = newfunc; + return TRUE; +} + +/* Create a new hash table with the default number of entries. */ + +bfd_boolean +bfd_hash_table_init (struct bfd_hash_table *table, + struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int entsize) +{ + return bfd_hash_table_init_n (table, newfunc, entsize, + bfd_default_hash_table_size); +} + +/* Free a hash table. */ + +void +bfd_hash_table_free (struct bfd_hash_table *table) +{ + objalloc_free (table->memory); + table->memory = NULL; +} + +/* Look up a string in a hash table. */ + +struct bfd_hash_entry * +bfd_hash_lookup (struct bfd_hash_table *table, + const char *string, + bfd_boolean create, + bfd_boolean copy) +{ + const unsigned char *s; + unsigned long hash; + 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 != NULL; + hashp = hashp->next) + { + if (hashp->hash == hash + && strcmp (hashp->string, string) == 0) + return hashp; + } + + if (! create) + return NULL; + + hashp = (*table->newfunc) (NULL, table, string); + if (hashp == NULL) + return NULL; + if (copy) + { + char *new; + + new = objalloc_alloc ((struct objalloc *) table->memory, len + 1); + if (!new) + { + bfd_set_error (bfd_error_no_memory); + return 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 (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) != NULL; + pph = &(*pph)->next) + { + if (*pph == old) + { + *pph = nw; + return; + } + } + + abort (); +} + +/* Allocate space in a hash table. */ + +void * +bfd_hash_allocate (struct bfd_hash_table *table, + unsigned int size) +{ + void * ret; + + ret = objalloc_alloc ((struct objalloc *) table->memory, size); + if (ret == NULL && size != 0) + bfd_set_error (bfd_error_no_memory); + return ret; +} + +/* Base method for creating a new hash table entry. */ + +struct bfd_hash_entry * +bfd_hash_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string ATTRIBUTE_UNUSED) +{ + if (entry == NULL) + entry = bfd_hash_allocate (table, sizeof (* entry)); + return entry; +} + +/* Traverse a hash table. */ + +void +bfd_hash_traverse (struct bfd_hash_table *table, + bfd_boolean (*func) (struct bfd_hash_entry *, void *), + void * 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; + } +} + +void +bfd_hash_set_default_size (bfd_size_type hash_size) +{ + /* Extend this prime list if you want more granularity of hash table size. */ + static const bfd_size_type hash_size_primes[] = + { + 251, 509, 1021, 2039, 4051, 8599, 16699, 32749 + }; + size_t index; + + /* Work out best prime number near the hash_size. */ + for (index = 0; index < ARRAY_SIZE (hash_size_primes) - 1; ++index) + if (hash_size <= hash_size_primes[index]) + break; + + bfd_default_hash_table_size = hash_size_primes[index]; +} + +/* 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; +}; + +/* Routine to create an entry in a strtab. */ + +static struct bfd_hash_entry * +strtab_hash_newfunc (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 == NULL) + ret = bfd_hash_allocate (table, sizeof (* ret)); + if (ret == 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 (void) +{ + struct bfd_strtab_hash *table; + bfd_size_type amt = sizeof (* table); + + table = bfd_malloc (amt); + if (table == NULL) + return NULL; + + if (!bfd_hash_table_init (&table->table, strtab_hash_newfunc, + sizeof (struct strtab_hash_entry))) + { + 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 (void) +{ + struct bfd_strtab_hash *ret; + + ret = _bfd_stringtab_init (); + if (ret != NULL) + ret->xcoff = TRUE; + return ret; +} + +/* Free a strtab. */ + +void +_bfd_stringtab_free (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 (struct bfd_strtab_hash *tab, + const char *str, + bfd_boolean hash, + bfd_boolean copy) +{ + 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 = bfd_hash_allocate (&tab->table, sizeof (* entry)); + if (entry == NULL) + return (bfd_size_type) -1; + if (! copy) + entry->root.string = str; + else + { + char *n; + + n = 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 (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 (bfd *abfd, struct bfd_strtab_hash *tab) +{ + bfd_boolean xcoff; + 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 ((void *) buf, (bfd_size_type) 2, abfd) != 2) + return FALSE; + } + + if (bfd_bwrite ((void *) str, (bfd_size_type) len, abfd) != len) + return FALSE; + } + + return TRUE; +} diff --git a/contrib/binutils-2.17/bfd/ihex.c b/contrib/binutils-2.17/bfd/ihex.c new file mode 100644 index 0000000000..fb2ab96c99 --- /dev/null +++ b/contrib/binutils-2.17/bfd/ihex.c @@ -0,0 +1,996 @@ +/* BFD back-end for Intel Hex objects. + Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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" + +/* 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 (void) +{ + static bfd_boolean inited; + + if (! inited) + { + inited = TRUE; + hex_init (); + } +} + +/* Create an ihex object. */ + +static bfd_boolean +ihex_mkobject (bfd *abfd) +{ + struct ihex_data_struct *tdata; + + tdata = bfd_alloc (abfd, sizeof (* tdata)); + 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 (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 (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) + (_("%B:%d: unexpected character `%s' in Intel Hex file"), + 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 (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_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) + (_("%B:%u: bad checksum in Intel Hex file (expected %u, found %u)"), + 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->size == extbase + segbase + addr) + { + /* This data goes at the end of the section we are + currently building. */ + sec->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 = 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->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) + (_("%B:%u: bad extended address record length in Intel Hex file"), + 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) + (_("%B:%u: bad extended start address length in Intel Hex file"), + 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) + (_("%B:%u: bad extended linear address record length in Intel Hex file"), + 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) + (_("%B:%u: bad extended linear start address length in Intel Hex file"), + 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) + (_("%B:%u: unrecognized ihex type %u in Intel Hex file"), + 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 (bfd *abfd) +{ + void * 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 (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) + (_("%B: internal error in ihex_read_section"), abfd); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + if (len * 2 > bufsize) + { + buf = 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->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->size) + { + (*_bfd_error_handler) + (_("%B: bad section length in ihex_read_section"), 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 (bfd *abfd, + asection *section, + void * location, + file_ptr offset, + bfd_size_type count) +{ + if (section->used_by_bfd == NULL) + { + section->used_by_bfd = bfd_alloc (abfd, section->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 (bfd *abfd, + asection *section, + const void * location, + file_ptr offset, + bfd_size_type count) +{ + struct ihex_data_list *n; + bfd_byte *data; + struct ihex_data_struct *tdata; + + if (count == 0 + || (section->flags & SEC_ALLOC) == 0 + || (section->flags & SEC_LOAD) == 0) + return TRUE; + + n = bfd_alloc (abfd, sizeof (* n)); + if (n == NULL) + return FALSE; + + data = 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 + { + 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 (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 (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 (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. */ + +static int +ihex_sizeof_headers (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_canonicalize_symtab ((long (*) (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_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) +#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_find_inliner_info _bfd_nosymbols_find_inliner_info +#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 (*) (bfd *, asection *)) bfd_0l) +#define ihex_canonicalize_reloc ((long (*) (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_is_group_section bfd_generic_is_group_section +#define ihex_bfd_discard_group bfd_generic_discard_group +#define ihex_section_already_linked _bfd_generic_section_already_linked +#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, /* Headers. */ + + { + _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, + + NULL +}; diff --git a/contrib/binutils-2.17/bfd/init.c b/contrib/binutils-2.17/bfd/init.c new file mode 100644 index 0000000000..a34acbf9fa --- /dev/null +++ b/contrib/binutils-2.17/bfd/init.c @@ -0,0 +1,54 @@ +/* bfd initialization stuff + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 2003 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* +SECTION + Initialization + +SUBSECTION + Initialization functions + + These are the functions that handle initializing a BFD. +*/ + +/* +FUNCTION + bfd_init + +SYNOPSIS + void bfd_init (void); + +DESCRIPTION + This routine must be called before any other BFD function to + initialize magical internal data structures. +*/ + +/* Actually, there is currently nothing for this function to do. + However, someday it may be needed, so keep it around. */ + +void +bfd_init (void) +{ +} diff --git a/contrib/binutils-2.17/bfd/libaout.h b/contrib/binutils-2.17/bfd/libaout.h new file mode 100644 index 0000000000..bb3ee80826 --- /dev/null +++ b/contrib/binutils-2.17/bfd/libaout.h @@ -0,0 +1,685 @@ +/* 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, 2003, 2004, 2005, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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. */ + +#define H_PUT_64 bfd_h_put_64 +#define H_PUT_32 bfd_h_put_32 +#define H_PUT_16 bfd_h_put_16 +#define H_PUT_8 bfd_h_put_8 +#define H_PUT_S64 bfd_h_put_signed_64 +#define H_PUT_S32 bfd_h_put_signed_32 +#define H_PUT_S16 bfd_h_put_signed_16 +#define H_PUT_S8 bfd_h_put_signed_8 +#define H_GET_64 bfd_h_get_64 +#define H_GET_32 bfd_h_get_32 +#define H_GET_16 bfd_h_get_16 +#define H_GET_8 bfd_h_get_8 +#define H_GET_S64 bfd_h_get_signed_64 +#define H_GET_S32 bfd_h_get_signed_32 +#define H_GET_S16 bfd_h_get_signed_16 +#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 (*) (struct bfd_link_hash_entry *, void *)) (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) (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) + (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) + (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) + (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) + (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) + (struct bfd_link_info *info, bfd *input_bfd, + asection *input_section, struct aout_link_hash_entry *h, + void * 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) (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_POWERPC_NETBSD = 149, /* NetBSD/powerpc (big-endian) binary. */ + M_VAX4K_NETBSD = 150, /* NetBSD/vax 4K pages binary. */ + M_MIPS1 = 151, /* MIPS R2000/R3000 binary. */ + M_MIPS2 = 152, /* MIPS R4000/R6000 binary. */ + M_88K_OPENBSD = 153, /* OpenBSD/m88k binary. */ + M_HPPA_OPENBSD = 154, /* OpenBSD/hppa binary. */ + M_SPARC64_NETBSD = 156, /* NetBSD/sparc64 binary. */ + M_X86_64_NETBSD = 157, /* NetBSD/amd64 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. */ + void * 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. */ + void * 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 = (void *)&(v)->relocs) + +/* Prototype declarations for functions defined in aoutx.h. */ + +extern bfd_boolean NAME (aout, squirt_out_relocs) + (bfd *, asection *); + +extern bfd_boolean NAME (aout, make_sections) + (bfd *); + +extern const bfd_target * NAME (aout, some_aout_object_p) + (bfd *, struct internal_exec *, const bfd_target *(*) (bfd *)); + +extern bfd_boolean NAME (aout, mkobject) + (bfd *); + +extern enum machine_type NAME (aout, machine_type) + (enum bfd_architecture, unsigned long, bfd_boolean *); + +extern bfd_boolean NAME (aout, set_arch_mach) + (bfd *, enum bfd_architecture, unsigned long); + +extern bfd_boolean NAME (aout, new_section_hook) + (bfd *, asection *); + +extern bfd_boolean NAME (aout, set_section_contents) + (bfd *, sec_ptr, const void *, file_ptr, bfd_size_type); + +extern asymbol * NAME (aout, make_empty_symbol) + (bfd *); + +extern bfd_boolean NAME (aout, translate_symbol_table) + (bfd *, aout_symbol_type *, struct external_nlist *, bfd_size_type, + char *, bfd_size_type, bfd_boolean); + +extern bfd_boolean NAME (aout, slurp_symbol_table) + (bfd *); + +extern bfd_boolean NAME (aout, write_syms) + (bfd *); + +extern void NAME (aout, reclaim_symbol_table) + (bfd *); + +extern long NAME (aout, get_symtab_upper_bound) + (bfd *); + +extern long NAME (aout, canonicalize_symtab) + (bfd *, asymbol **); + +extern void NAME (aout, swap_ext_reloc_in) + (bfd *, struct reloc_ext_external *, arelent *, asymbol **, + bfd_size_type); + +extern void NAME (aout, swap_std_reloc_in) + (bfd *, struct reloc_std_external *, arelent *, asymbol **, + bfd_size_type); + +extern reloc_howto_type * NAME (aout, reloc_type_lookup) + (bfd *, bfd_reloc_code_real_type); + +extern bfd_boolean NAME (aout, slurp_reloc_table) + (bfd *, sec_ptr, asymbol **); + +extern long NAME (aout, canonicalize_reloc) + (bfd *, sec_ptr, arelent **, asymbol **); + +extern long NAME (aout, get_reloc_upper_bound) + (bfd *, sec_ptr); + +extern void NAME (aout, reclaim_reloc) + (bfd *, sec_ptr); + +extern alent * NAME (aout, get_lineno) + (bfd *, asymbol *); + +extern void NAME (aout, print_symbol) + (bfd *, void *, asymbol *, bfd_print_symbol_type); + +extern void NAME (aout, get_symbol_info) + (bfd *, asymbol *, symbol_info *); + +extern bfd_boolean NAME (aout, find_nearest_line) + (bfd *, asection *, asymbol **, bfd_vma, const char **, + const char **, unsigned int *); + +extern long NAME (aout, read_minisymbols) + (bfd *, bfd_boolean, void * *, unsigned int *); + +extern asymbol * NAME (aout, minisymbol_to_symbol) + (bfd *, bfd_boolean, const void *, asymbol *); + +extern int NAME (aout, sizeof_headers) + (bfd *, bfd_boolean); + +extern bfd_boolean NAME (aout, adjust_sizes_and_vmas) + (bfd *, bfd_size_type *, file_ptr *); + +extern void NAME (aout, swap_exec_header_in) + (bfd *, struct external_exec *, struct internal_exec *); + +extern void NAME (aout, swap_exec_header_out) + (bfd *, struct internal_exec *, struct external_exec *); + +extern struct bfd_hash_entry * NAME (aout, link_hash_newfunc) + (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); + +extern bfd_boolean NAME (aout, link_hash_table_init) + (struct aout_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int); + +extern struct bfd_link_hash_table * NAME (aout, link_hash_table_create) + (bfd *); + +extern bfd_boolean NAME (aout, link_add_symbols) + (bfd *, struct bfd_link_info *); + +extern bfd_boolean NAME (aout, final_link) + (bfd *, struct bfd_link_info *, + void (*) (bfd *, file_ptr *, file_ptr *, file_ptr *)); + +extern bfd_boolean NAME (aout, bfd_free_cached_info) + (bfd *); + +#define aout_32_find_inliner_info _bfd_nosymbols_find_inliner_info +#if 0 /* Are these needed? */ +#define aout_16_find_inliner_info _bfd_nosymbols_find_inliner_info +#define aout_64_find_inliner_info _bfd_nosymbols_find_inliner_info +#endif + +/* 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 aout_32_bfd_is_target_special_symbol +#define aout_32_bfd_is_target_special_symbol \ + ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) +#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 (& 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) != 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)->size) \ + && ((sec)->vma + (sec)->size) <= obj_datasec (abfd)->vma \ + && ((abfd)->flags & D_PAGED) != 0) + +#endif /* ! defined (LIBAOUT_H) */ diff --git a/contrib/binutils-2.17/bfd/libbfd-in.h b/contrib/binutils-2.17/bfd/libbfd-in.h new file mode 100644 index 0000000000..ee2484f25c --- /dev/null +++ b/contrib/binutils-2.17/bfd/libbfd-in.h @@ -0,0 +1,728 @@ +/* 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, 2003, 2004, 2005, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "hashtab.h" + +/* 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 = (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; +}; + +struct section_hash_entry +{ + struct bfd_hash_entry root; + asection section; +}; + +/* 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 */ + htab_t 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 */ + bfd_size_type extended_names_size; /* Size of extended names */ + /* 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. */ + void *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 void *bfd_malloc + (bfd_size_type); +extern void *bfd_realloc + (void *, bfd_size_type); +extern void *bfd_zmalloc + (bfd_size_type); +extern void *bfd_malloc2 + (bfd_size_type, bfd_size_type); +extern void *bfd_realloc2 + (void *, bfd_size_type, bfd_size_type); +extern void *bfd_zmalloc2 + (bfd_size_type, bfd_size_type); + +extern void _bfd_default_error_handler (const char *s, ...); +extern bfd_error_handler_type _bfd_error_handler; + +/* These routines allocate and free things on the BFD's objalloc. */ + +extern void *bfd_alloc + (bfd *, bfd_size_type); +extern void *bfd_zalloc + (bfd *, bfd_size_type); +extern void *bfd_alloc2 + (bfd *, bfd_size_type, bfd_size_type); +extern void *bfd_zalloc2 + (bfd *, bfd_size_type, bfd_size_type); +extern void bfd_release + (bfd *, void *); + +bfd * _bfd_create_empty_archive_element_shell + (bfd *obfd); +bfd * _bfd_look_for_bfd_in_cache + (bfd *, file_ptr); +bfd_boolean _bfd_add_bfd_to_archive_cache + (bfd *, file_ptr, bfd *); +bfd_boolean _bfd_generic_mkarchive + (bfd *abfd); +const bfd_target *bfd_generic_archive_p + (bfd *abfd); +bfd_boolean bfd_slurp_armap + (bfd *abfd); +bfd_boolean bfd_slurp_bsd_armap_f2 + (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 + (bfd *abfd); +extern bfd_boolean _bfd_construct_extended_name_table + (bfd *, bfd_boolean, char **, bfd_size_type *); +bfd_boolean _bfd_write_archive_contents + (bfd *abfd); +bfd_boolean _bfd_compute_and_write_armap + (bfd *, unsigned int elength); +bfd *_bfd_get_elt_at_filepos + (bfd *archive, file_ptr filepos); +extern bfd *_bfd_generic_get_elt_at_index + (bfd *, symindex); +bfd * _bfd_new_bfd + (void); +void _bfd_delete_bfd + (bfd *); + +bfd_boolean bfd_false + (bfd *ignore); +bfd_boolean bfd_true + (bfd *ignore); +void *bfd_nullvoidptr + (bfd *ignore); +int bfd_0 + (bfd *ignore); +unsigned int bfd_0u + (bfd *ignore); +long bfd_0l + (bfd *ignore); +long _bfd_n1 + (bfd *ignore); +void bfd_void + (bfd *ignore); + +bfd *_bfd_new_bfd_contained_in + (bfd *); +const bfd_target *_bfd_dummy_target + (bfd *abfd); + +void bfd_dont_truncate_arname + (bfd *abfd, const char *filename, char *hdr); +void bfd_bsd_truncate_arname + (bfd *abfd, const char *filename, char *hdr); +void bfd_gnu_truncate_arname + (bfd *abfd, const char *filename, char *hdr); + +bfd_boolean bsd_write_armap + (bfd *arch, unsigned int elength, struct orl *map, unsigned int orl_count, + int stridx); + +bfd_boolean coff_write_armap + (bfd *arch, unsigned int elength, struct orl *map, unsigned int orl_count, + int stridx); + +extern void *_bfd_generic_read_ar_hdr + (bfd *); +extern void _bfd_ar_spacepad + (char *, size_t, const char *, long); + +extern void *_bfd_generic_read_ar_hdr_mag + (bfd *, const char *); + +bfd * bfd_generic_openr_next_archived_file + (bfd *archive, bfd *last_file); + +int bfd_generic_stat_arch_elt + (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 (*) (bfd *, asection *)) bfd_true) +extern bfd_boolean _bfd_generic_get_section_contents + (bfd *, asection *, void *, file_ptr, bfd_size_type); +extern bfd_boolean _bfd_generic_get_section_contents_in_window + (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 (*) (bfd *, bfd *)) bfd_true) +#define _bfd_generic_bfd_merge_private_bfd_data \ + ((bfd_boolean (*) (bfd *, bfd *)) bfd_true) +#define _bfd_generic_bfd_set_private_flags \ + ((bfd_boolean (*) (bfd *, flagword)) bfd_true) +#define _bfd_generic_bfd_copy_private_section_data \ + ((bfd_boolean (*) (bfd *, asection *, bfd *, asection *)) bfd_true) +#define _bfd_generic_bfd_copy_private_symbol_data \ + ((bfd_boolean (*) (bfd *, asymbol *, bfd *, asymbol *)) bfd_true) +#define _bfd_generic_bfd_copy_private_header_data \ + ((bfd_boolean (*) (bfd *, bfd *)) bfd_true) +#define _bfd_generic_bfd_print_private_bfd_data \ + ((bfd_boolean (*) (bfd *, void *)) bfd_true) + +extern bfd_boolean _bfd_generic_init_private_section_data + (bfd *, asection *, bfd *, asection *, struct bfd_link_info *); + +/* 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 + (bfd *); +extern int _bfd_nocore_core_file_failing_signal + (bfd *); +extern bfd_boolean _bfd_nocore_core_file_matches_executable_p + (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 (*) (bfd *, char **, bfd_size_type *, const char **)) \ + bfd_false) +#define _bfd_noarchive_truncate_arname \ + ((void (*) (bfd *, const char *, char *)) bfd_void) +#define _bfd_noarchive_write_armap \ + ((bfd_boolean (*) (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 *(*) (bfd *, bfd *)) bfd_nullvoidptr) +#define _bfd_noarchive_get_elt_at_index \ + ((bfd *(*) (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 + (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 + (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 + (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_canonicalize_symtab \ + ((long (*) (bfd *, asymbol **)) _bfd_n1) +#define _bfd_nosymbols_make_empty_symbol _bfd_generic_make_empty_symbol +#define _bfd_nosymbols_print_symbol \ + ((void (*) (bfd *, void *, asymbol *, bfd_print_symbol_type)) bfd_void) +#define _bfd_nosymbols_get_symbol_info \ + ((void (*) (bfd *, asymbol *, symbol_info *)) bfd_void) +#define _bfd_nosymbols_bfd_is_local_label_name \ + ((bfd_boolean (*) (bfd *, const char *)) bfd_false) +#define _bfd_nosymbols_bfd_is_target_special_symbol \ + ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) +#define _bfd_nosymbols_get_lineno \ + ((alent *(*) (bfd *, asymbol *)) bfd_nullvoidptr) +#define _bfd_nosymbols_find_nearest_line \ + ((bfd_boolean (*) (bfd *, asection *, asymbol **, bfd_vma, const char **, \ + const char **, unsigned int *)) \ + bfd_false) +#define _bfd_nosymbols_find_inliner_info \ + ((bfd_boolean (*) (bfd *, const char **, const char **, unsigned int *)) \ + bfd_false) +#define _bfd_nosymbols_bfd_make_debug_symbol \ + ((asymbol *(*) (bfd *, void *, unsigned long)) bfd_nullvoidptr) +#define _bfd_nosymbols_read_minisymbols \ + ((long (*) (bfd *, bfd_boolean, void **, unsigned int *)) _bfd_n1) +#define _bfd_nosymbols_minisymbol_to_symbol \ + ((asymbol *(*) (bfd *, bfd_boolean, const void *, 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 (*) (bfd *, asection *)) _bfd_n1) +#define _bfd_norelocs_canonicalize_reloc \ + ((long (*) (bfd *, asection *, arelent **, asymbol **)) _bfd_n1) +#define _bfd_norelocs_bfd_reloc_type_lookup \ + ((reloc_howto_type *(*) (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 (*) (bfd *, enum bfd_architecture, unsigned long)) \ + bfd_false) +#define _bfd_nowrite_set_section_contents \ + ((bfd_boolean (*) (bfd *, asection *, const void *, 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 + (bfd *, asection *, const void *, 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 (*) (bfd *, bfd_boolean)) bfd_0) +#define _bfd_nolink_bfd_get_relocated_section_contents \ + ((bfd_byte *(*) (bfd *, struct bfd_link_info *, struct bfd_link_order *, \ + bfd_byte *, bfd_boolean, asymbol **)) \ + bfd_nullvoidptr) +#define _bfd_nolink_bfd_relax_section \ + ((bfd_boolean (*) \ + (bfd *, asection *, struct bfd_link_info *, bfd_boolean *)) \ + bfd_false) +#define _bfd_nolink_bfd_gc_sections \ + ((bfd_boolean (*) (bfd *, struct bfd_link_info *)) \ + bfd_false) +#define _bfd_nolink_bfd_merge_sections \ + ((bfd_boolean (*) (bfd *, struct bfd_link_info *)) \ + bfd_false) +#define _bfd_nolink_bfd_is_group_section \ + ((bfd_boolean (*) (bfd *, const struct bfd_section *)) \ + bfd_false) +#define _bfd_nolink_bfd_discard_group \ + ((bfd_boolean (*) (bfd *, struct bfd_section *)) \ + bfd_false) +#define _bfd_nolink_bfd_link_hash_table_create \ + ((struct bfd_link_hash_table *(*) (bfd *)) bfd_nullvoidptr) +#define _bfd_nolink_bfd_link_hash_table_free \ + ((void (*) (struct bfd_link_hash_table *)) bfd_void) +#define _bfd_nolink_bfd_link_add_symbols \ + ((bfd_boolean (*) (bfd *, struct bfd_link_info *)) bfd_false) +#define _bfd_nolink_bfd_link_just_syms \ + ((void (*) (asection *, struct bfd_link_info *)) bfd_void) +#define _bfd_nolink_bfd_final_link \ + ((bfd_boolean (*) (bfd *, struct bfd_link_info *)) bfd_false) +#define _bfd_nolink_bfd_link_split_section \ + ((bfd_boolean (*) (bfd *, struct bfd_section *)) bfd_false) +#define _bfd_nolink_section_already_linked \ + ((void (*) (bfd *, struct bfd_section *)) bfd_void) + +/* 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 (*) (bfd *, asymbol **)) _bfd_n1) +#define _bfd_nodynamic_get_synthetic_symtab \ + ((long (*) (bfd *, long, asymbol **, long, asymbol **, asymbol **)) _bfd_n1) +#define _bfd_nodynamic_get_dynamic_reloc_upper_bound _bfd_n1 +#define _bfd_nodynamic_canonicalize_dynamic_reloc \ + ((long (*) (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 + (bfd *, const char *); + +/* Generic minisymbol routines. */ +extern long _bfd_generic_read_minisymbols + (bfd *, bfd_boolean, void **, unsigned int *); +extern asymbol *_bfd_generic_minisymbol_to_symbol + (bfd *, bfd_boolean, const void *, asymbol *); + +/* Find the nearest line using .stab/.stabstr sections. */ +extern bfd_boolean _bfd_stab_section_find_nearest_line + (bfd *, asymbol **, asection *, bfd_vma, bfd_boolean *, + const char **, const char **, unsigned int *, void **); + +/* Find the nearest line using DWARF 1 debugging information. */ +extern bfd_boolean _bfd_dwarf1_find_nearest_line + (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 + (bfd *, asection *, asymbol **, bfd_vma, const char **, const char **, + unsigned int *, unsigned int, void **); + +/* Find the line using DWARF 2 debugging information. */ +extern bfd_boolean _bfd_dwarf2_find_line + (bfd *, asymbol **, asymbol *, const char **, + unsigned int *, unsigned int, void **); + +bfd_boolean _bfd_generic_find_line + (bfd *, asymbol **, asymbol *, const char **, unsigned int *); + +/* Find inliner info after calling bfd_find_nearest_line. */ +extern bfd_boolean _bfd_dwarf2_find_inliner_info + (bfd *, const char **, const char **, unsigned int *, void **); + +/* Create a new section entry. */ +extern struct bfd_hash_entry *bfd_section_hash_newfunc + (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 + (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 + (struct bfd_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int); + +/* Generic link hash table creation routine. */ +extern struct bfd_link_hash_table *_bfd_generic_link_hash_table_create + (bfd *); + +/* Generic link hash table destruction routine. */ +extern void _bfd_generic_link_hash_table_free + (struct bfd_link_hash_table *); + +/* Generic add symbol routine. */ +extern bfd_boolean _bfd_generic_link_add_symbols + (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 + (bfd *, struct bfd_link_info *); + +/* Generic archive add symbol routine. */ +extern bfd_boolean _bfd_generic_link_add_archive_symbols + (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 + (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 + (asection *, struct bfd_link_info *); + +/* Generic link routine. */ +extern bfd_boolean _bfd_generic_final_link + (bfd *, struct bfd_link_info *); + +extern bfd_boolean _bfd_generic_link_split_section + (bfd *, struct bfd_section *); + +extern void _bfd_generic_section_already_linked + (bfd *, struct bfd_section *); + +/* Generic reloc_link_order processing routine. */ +extern bfd_boolean _bfd_generic_reloc_link_order + (bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *); + +/* Default link order processing routine. */ +extern bfd_boolean _bfd_default_link_order + (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 + (struct bfd_link_order *); + +/* Final link relocation routine. */ +extern bfd_reloc_status_type _bfd_final_link_relocate + (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 + (reloc_howto_type *, bfd *, bfd_vma, bfd_byte *); + +/* Link stabs in sections in the first pass. */ + +extern bfd_boolean _bfd_link_section_stabs + (bfd *, struct stab_info *, asection *, asection *, void **, + bfd_size_type *); + +/* Eliminate stabs for discarded functions and symbols. */ +extern bfd_boolean _bfd_discard_section_stabs + (bfd *, asection *, void *, bfd_boolean (*) (bfd_vma, void *), void *); + +/* Write out the .stab section when linking stabs in sections. */ + +extern bfd_boolean _bfd_write_section_stabs + (bfd *, struct stab_info *, asection *, void **, bfd_byte *); + +/* Write out the .stabstr string table when linking stabs in sections. */ + +extern bfd_boolean _bfd_write_stab_strings + (bfd *, struct stab_info *); + +/* Find an offset within a .stab section when linking stabs in + sections. */ + +extern bfd_vma _bfd_stab_section_offset + (asection *, void *, bfd_vma); + +/* Register a SEC_MERGE section as a candidate for merging. */ + +extern bfd_boolean _bfd_add_merge_section + (bfd *, void **, asection *, void **); + +/* Attempt to merge SEC_MERGE sections. */ + +extern bfd_boolean _bfd_merge_sections + (bfd *, struct bfd_link_info *, void *, void (*) (bfd *, asection *)); + +/* Write out a merged section. */ + +extern bfd_boolean _bfd_write_merged_section + (bfd *, asection *, void *); + +/* Find an offset within a modified SEC_MERGE section. */ + +extern bfd_vma _bfd_merged_section_offset + (bfd *, asection **, void *, bfd_vma); + +/* Create a string table. */ +extern struct bfd_strtab_hash *_bfd_stringtab_init + (void); + +/* Create an XCOFF .debug section style string table. */ +extern struct bfd_strtab_hash *_bfd_xcoff_stringtab_init + (void); + +/* Free a string table. */ +extern void _bfd_stringtab_free + (struct bfd_strtab_hash *); + +/* Get the size of a string table. */ +extern bfd_size_type _bfd_stringtab_size + (struct bfd_strtab_hash *); + +/* Add a string to a string table. */ +extern bfd_size_type _bfd_stringtab_add + (struct bfd_strtab_hash *, const char *, bfd_boolean hash, bfd_boolean copy); + +/* Write out a string table. */ +extern bfd_boolean _bfd_stringtab_emit + (bfd *, struct bfd_strtab_hash *); + +/* Check that endianness of input and output file match. */ +extern bfd_boolean _bfd_generic_verify_endian_match + (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 + (const char*,int); + +#define BFD_ASSERT(x) \ + do { if (!(x)) bfd_assert(__FILE__,__LINE__); } while (0) + +#define BFD_FAIL() \ + do { bfd_assert(__FILE__,__LINE__); } while (0) + +extern void _bfd_abort + (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__) + +/* Manipulate a system FILE but using BFD's "file_ptr", rather than + the system "off_t" or "off64_t", as the offset. */ +extern file_ptr real_ftell (FILE *file); +extern int real_fseek (FILE *file, file_ptr offset, int whence); +extern FILE *real_fopen (const char *filename, const char *modes); + +/* 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 + (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 + (void *, bfd_byte *); +extern bfd_boolean _bfd_ecoff_get_accumulated_sym + (void *, bfd_byte *); +extern bfd_boolean _bfd_ecoff_get_accumulated_ss + (void *, bfd_byte *); + +extern bfd_vma _bfd_get_gp_value + (bfd *); +extern void _bfd_set_gp_value + (bfd *, bfd_vma); + +/* Function shared by the COFF and ELF SH backends, which have no + other common header files. */ + +#ifndef _bfd_sh_align_load_span +extern bfd_boolean _bfd_sh_align_load_span + (bfd *, asection *, bfd_byte *, + bfd_boolean (*) (bfd *, asection *, void *, bfd_byte *, bfd_vma), + void *, bfd_vma **, bfd_vma *, bfd_vma, bfd_vma, bfd_boolean *); +#endif + +/* 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. */ + +struct bfd_section_already_linked_hash_entry +{ + struct bfd_hash_entry root; + struct bfd_section_already_linked *entry; +}; + +struct bfd_section_already_linked +{ + struct bfd_section_already_linked *next; + asection *sec; +}; + +extern struct bfd_section_already_linked_hash_entry * + bfd_section_already_linked_table_lookup (const char *); +extern void bfd_section_already_linked_table_insert + (struct bfd_section_already_linked_hash_entry *, asection *); +extern void bfd_section_already_linked_table_traverse + (bfd_boolean (*) (struct bfd_section_already_linked_hash_entry *, + void *), void *); + +extern bfd_vma read_unsigned_leb128 (bfd *, bfd_byte *, unsigned int *); +extern bfd_signed_vma read_signed_leb128 (bfd *, bfd_byte *, unsigned int *); + diff --git a/contrib/binutils-2.17/bfd/libbfd.c b/contrib/binutils-2.17/bfd/libbfd.c new file mode 100644 index 0000000000..57cfabcd46 --- /dev/null +++ b/contrib/binutils-2.17/bfd/libbfd.c @@ -0,0 +1,1045 @@ +/* Assorted BFD support routines, only used internally. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004, 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#ifndef HAVE_GETPAGESIZE +#define getpagesize() 2048 +#endif + +/* +SECTION + Implementation details + +SUBSECTION + 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 (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 (bfd *ignore ATTRIBUTE_UNUSED) +{ + return TRUE; +} + +/* A routine which is used in target vectors for unsupported + operations which return a pointer value. */ + +void * +bfd_nullvoidptr (bfd *ignore ATTRIBUTE_UNUSED) +{ + bfd_set_error (bfd_error_invalid_operation); + return NULL; +} + +int +bfd_0 (bfd *ignore ATTRIBUTE_UNUSED) +{ + return 0; +} + +unsigned int +bfd_0u (bfd *ignore ATTRIBUTE_UNUSED) +{ + return 0; +} + +long +bfd_0l (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 (bfd *ignore_abfd ATTRIBUTE_UNUSED) +{ + bfd_set_error (bfd_error_invalid_operation); + return -1; +} + +void +bfd_void (bfd *ignore ATTRIBUTE_UNUSED) +{ +} + +bfd_boolean +_bfd_nocore_core_file_matches_executable_p + (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 (bfd *ignore_abfd ATTRIBUTE_UNUSED) +{ + bfd_set_error (bfd_error_invalid_operation); + return NULL; +} + +/* Routine to handle core_file_failing_signal entry point for targets + without core file support. */ + +int +_bfd_nocore_core_file_failing_signal (bfd *ignore_abfd ATTRIBUTE_UNUSED) +{ + bfd_set_error (bfd_error_invalid_operation); + return 0; +} + +const bfd_target * +_bfd_dummy_target (bfd *ignore_abfd ATTRIBUTE_UNUSED) +{ + bfd_set_error (bfd_error_wrong_format); + return 0; +} + +/* Allocate memory using malloc. */ + +void * +bfd_malloc (bfd_size_type size) +{ + void *ptr; + + if (size != (size_t) size) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + ptr = malloc ((size_t) size); + if (ptr == NULL && (size_t) size != 0) + bfd_set_error (bfd_error_no_memory); + + return ptr; +} + +/* Allocate memory using malloc, nmemb * size with overflow checking. */ + +void * +bfd_malloc2 (bfd_size_type nmemb, bfd_size_type size) +{ + void *ptr; + + if ((nmemb | size) >= HALF_BFD_SIZE_TYPE + && size != 0 + && nmemb > ~(bfd_size_type) 0 / size) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + size *= nmemb; + + if (size != (size_t) size) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + 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. */ + +void * +bfd_realloc (void *ptr, bfd_size_type size) +{ + void *ret; + + if (size != (size_t) size) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + if (ptr == NULL) + ret = malloc ((size_t) size); + else + ret = realloc (ptr, (size_t) size); + + if (ret == NULL && (size_t) size != 0) + bfd_set_error (bfd_error_no_memory); + + return ret; +} + +/* Reallocate memory using realloc, nmemb * size with overflow checking. */ + +void * +bfd_realloc2 (void *ptr, bfd_size_type nmemb, bfd_size_type size) +{ + void *ret; + + if ((nmemb | size) >= HALF_BFD_SIZE_TYPE + && size != 0 + && nmemb > ~(bfd_size_type) 0 / size) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + size *= nmemb; + + if (size != (size_t) size) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + if (ptr == NULL) + ret = malloc ((size_t) size); + else + ret = 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. */ + +void * +bfd_zmalloc (bfd_size_type size) +{ + void *ptr; + + if (size != (size_t) size) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + 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; +} + +/* Allocate memory using malloc (nmemb * size) with overflow checking + and clear it. */ + +void * +bfd_zmalloc2 (bfd_size_type nmemb, bfd_size_type size) +{ + void *ptr; + + if ((nmemb | size) >= HALF_BFD_SIZE_TYPE + && size != 0 + && nmemb > ~(bfd_size_type) 0 / size) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + size *= nmemb; + + if (size != (size_t) size) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + 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 (bfd *abfd, unsigned int i) +{ + bfd_byte buffer[4]; + bfd_putb32 ((bfd_vma) i, buffer); + return bfd_bwrite (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)) = (val) & 0xff)) +.#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)) +. +.{* Aliases for the above, which should eventually go away. *} +. +.#define H_PUT_64 bfd_h_put_64 +.#define H_PUT_32 bfd_h_put_32 +.#define H_PUT_16 bfd_h_put_16 +.#define H_PUT_8 bfd_h_put_8 +.#define H_PUT_S64 bfd_h_put_signed_64 +.#define H_PUT_S32 bfd_h_put_signed_32 +.#define H_PUT_S16 bfd_h_put_signed_16 +.#define H_PUT_S8 bfd_h_put_signed_8 +.#define H_GET_64 bfd_h_get_64 +.#define H_GET_32 bfd_h_get_32 +.#define H_GET_16 bfd_h_get_16 +.#define H_GET_8 bfd_h_get_8 +.#define H_GET_S64 bfd_h_get_signed_64 +.#define H_GET_S32 bfd_h_get_signed_32 +.#define H_GET_S16 bfd_h_get_signed_16 +.#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) (x) ^ 0x80000000) - 0x80000000) +#define EIGHT_GAZILLION ((bfd_int64_t) 1 << 63) +#define COERCE64(x) \ + (((bfd_int64_t) (x) ^ EIGHT_GAZILLION) - EIGHT_GAZILLION) + +bfd_vma +bfd_getb16 (const void *p) +{ + const bfd_byte *addr = p; + return (addr[0] << 8) | addr[1]; +} + +bfd_vma +bfd_getl16 (const void *p) +{ + const bfd_byte *addr = p; + return (addr[1] << 8) | addr[0]; +} + +bfd_signed_vma +bfd_getb_signed_16 (const void *p) +{ + const bfd_byte *addr = p; + return COERCE16 ((addr[0] << 8) | addr[1]); +} + +bfd_signed_vma +bfd_getl_signed_16 (const void *p) +{ + const bfd_byte *addr = p; + return COERCE16 ((addr[1] << 8) | addr[0]); +} + +void +bfd_putb16 (bfd_vma data, void *p) +{ + bfd_byte *addr = p; + addr[0] = (data >> 8) & 0xff; + addr[1] = data & 0xff; +} + +void +bfd_putl16 (bfd_vma data, void *p) +{ + bfd_byte *addr = p; + addr[0] = data & 0xff; + addr[1] = (data >> 8) & 0xff; +} + +bfd_vma +bfd_getb32 (const void *p) +{ + const bfd_byte *addr = p; + 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 v; +} + +bfd_vma +bfd_getl32 (const void *p) +{ + const bfd_byte *addr = p; + 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 v; +} + +bfd_signed_vma +bfd_getb_signed_32 (const void *p) +{ + const bfd_byte *addr = p; + 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 (const void *p) +{ + const bfd_byte *addr = p; + 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_uint64_t +bfd_getb64 (const void *p ATTRIBUTE_UNUSED) +{ +#ifdef BFD_HOST_64_BIT + const bfd_byte *addr = p; + bfd_uint64_t v; + + v = addr[0]; v <<= 8; + v |= addr[1]; v <<= 8; + v |= addr[2]; v <<= 8; + v |= addr[3]; v <<= 8; + v |= addr[4]; v <<= 8; + v |= addr[5]; v <<= 8; + v |= addr[6]; v <<= 8; + v |= addr[7]; + + return v; +#else + BFD_FAIL(); + return 0; +#endif +} + +bfd_uint64_t +bfd_getl64 (const void *p ATTRIBUTE_UNUSED) +{ +#ifdef BFD_HOST_64_BIT + const bfd_byte *addr = p; + bfd_uint64_t v; + + v = addr[7]; v <<= 8; + v |= addr[6]; v <<= 8; + v |= addr[5]; v <<= 8; + v |= addr[4]; v <<= 8; + v |= addr[3]; v <<= 8; + v |= addr[2]; v <<= 8; + v |= addr[1]; v <<= 8; + v |= addr[0]; + + return v; +#else + BFD_FAIL(); + return 0; +#endif + +} + +bfd_int64_t +bfd_getb_signed_64 (const void *p ATTRIBUTE_UNUSED) +{ +#ifdef BFD_HOST_64_BIT + const bfd_byte *addr = p; + bfd_uint64_t v; + + v = addr[0]; v <<= 8; + v |= addr[1]; v <<= 8; + v |= addr[2]; v <<= 8; + v |= addr[3]; v <<= 8; + v |= addr[4]; v <<= 8; + v |= addr[5]; v <<= 8; + v |= addr[6]; v <<= 8; + v |= addr[7]; + + return COERCE64 (v); +#else + BFD_FAIL(); + return 0; +#endif +} + +bfd_int64_t +bfd_getl_signed_64 (const void *p ATTRIBUTE_UNUSED) +{ +#ifdef BFD_HOST_64_BIT + const bfd_byte *addr = p; + bfd_uint64_t v; + + v = addr[7]; v <<= 8; + v |= addr[6]; v <<= 8; + v |= addr[5]; v <<= 8; + v |= addr[4]; v <<= 8; + v |= addr[3]; v <<= 8; + v |= addr[2]; v <<= 8; + v |= addr[1]; v <<= 8; + v |= addr[0]; + + return COERCE64 (v); +#else + BFD_FAIL(); + return 0; +#endif +} + +void +bfd_putb32 (bfd_vma data, void *p) +{ + bfd_byte *addr = p; + addr[0] = (data >> 24) & 0xff; + addr[1] = (data >> 16) & 0xff; + addr[2] = (data >> 8) & 0xff; + addr[3] = data & 0xff; +} + +void +bfd_putl32 (bfd_vma data, void *p) +{ + bfd_byte *addr = p; + addr[0] = data & 0xff; + addr[1] = (data >> 8) & 0xff; + addr[2] = (data >> 16) & 0xff; + addr[3] = (data >> 24) & 0xff; +} + +void +bfd_putb64 (bfd_uint64_t data ATTRIBUTE_UNUSED, void *p ATTRIBUTE_UNUSED) +{ +#ifdef BFD_HOST_64_BIT + bfd_byte *addr = p; + addr[0] = (data >> (7*8)) & 0xff; + addr[1] = (data >> (6*8)) & 0xff; + addr[2] = (data >> (5*8)) & 0xff; + addr[3] = (data >> (4*8)) & 0xff; + addr[4] = (data >> (3*8)) & 0xff; + addr[5] = (data >> (2*8)) & 0xff; + addr[6] = (data >> (1*8)) & 0xff; + addr[7] = (data >> (0*8)) & 0xff; +#else + BFD_FAIL(); +#endif +} + +void +bfd_putl64 (bfd_uint64_t data ATTRIBUTE_UNUSED, void *p ATTRIBUTE_UNUSED) +{ +#ifdef BFD_HOST_64_BIT + bfd_byte *addr = p; + addr[7] = (data >> (7*8)) & 0xff; + addr[6] = (data >> (6*8)) & 0xff; + addr[5] = (data >> (5*8)) & 0xff; + addr[4] = (data >> (4*8)) & 0xff; + addr[3] = (data >> (3*8)) & 0xff; + addr[2] = (data >> (2*8)) & 0xff; + addr[1] = (data >> (1*8)) & 0xff; + addr[0] = (data >> (0*8)) & 0xff; +#else + BFD_FAIL(); +#endif +} + +void +bfd_put_bits (bfd_uint64_t data, void *p, int bits, bfd_boolean big_p) +{ + bfd_byte *addr = 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] = data & 0xff; + data >>= 8; + } +} + +bfd_uint64_t +bfd_get_bits (const void *p, int bits, bfd_boolean big_p) +{ + const bfd_byte *addr = p; + bfd_uint64_t 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 (bfd *abfd, + sec_ptr section, + void *location, + file_ptr offset, + bfd_size_type count) +{ + bfd_size_type sz; + if (count == 0) + return TRUE; + + sz = section->rawsize ? section->rawsize : section->size; + if (offset + count > sz) + { + 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 + (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 + bfd_size_type sz; + + 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_zmalloc (sizeof (bfd_window_internal)); + if (w->i == NULL) + return FALSE; + w->i->data = 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); + } + sz = section->rawsize ? section->rawsize : section->size; + if (offset + count > sz + || ! 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 (bfd *abfd, + sec_ptr section, + const void *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 (bfd_vma x) +{ + unsigned int result = 0; + + while ((x = (x >> 1)) != 0) + ++result; + return result; +} + +bfd_boolean +bfd_generic_is_local_label_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 (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 = _("%B: compiled for a big endian system and target is little endian"); + else + msg = _("%B: compiled for a little endian system and target is big endian"); + + (*_bfd_error_handler) (msg, 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 (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; + } +} + +/* Helper function for reading uleb128 encoded data. */ + +bfd_vma +read_unsigned_leb128 (bfd *abfd ATTRIBUTE_UNUSED, + bfd_byte *buf, + unsigned int *bytes_read_ptr) +{ + bfd_vma result; + unsigned int num_read; + unsigned int shift; + unsigned char byte; + + result = 0; + shift = 0; + num_read = 0; + do + { + byte = bfd_get_8 (abfd, 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. */ + +bfd_signed_vma +read_signed_leb128 (bfd *abfd ATTRIBUTE_UNUSED, + bfd_byte *buf, + unsigned int *bytes_read_ptr) +{ + bfd_vma result; + unsigned int shift; + unsigned int num_read; + unsigned char byte; + + result = 0; + shift = 0; + num_read = 0; + do + { + byte = bfd_get_8 (abfd, buf); + buf ++; + num_read ++; + result |= (((bfd_vma) byte & 0x7f) << shift); + shift += 7; + } + while (byte & 0x80); + if (shift < 8 * sizeof (result) && (byte & 0x40)) + result |= (((bfd_vma) -1) << shift); + *bytes_read_ptr = num_read; + return result; +} + +bfd_boolean +_bfd_generic_find_line (bfd *abfd ATTRIBUTE_UNUSED, + asymbol **symbols ATTRIBUTE_UNUSED, + asymbol *symbol ATTRIBUTE_UNUSED, + const char **filename_ptr ATTRIBUTE_UNUSED, + unsigned int *linenumber_ptr ATTRIBUTE_UNUSED) +{ + return FALSE; +} + +bfd_boolean +_bfd_generic_init_private_section_data (bfd *ibfd ATTRIBUTE_UNUSED, + asection *isec ATTRIBUTE_UNUSED, + bfd *obfd ATTRIBUTE_UNUSED, + asection *osec ATTRIBUTE_UNUSED, + struct bfd_link_info *link_info ATTRIBUTE_UNUSED) +{ + return TRUE; +} diff --git a/contrib/binutils-2.17/bfd/libbfd.h b/contrib/binutils-2.17/bfd/libbfd.h new file mode 100644 index 0000000000..2a590a395a --- /dev/null +++ b/contrib/binutils-2.17/bfd/libbfd.h @@ -0,0 +1,1909 @@ +/* 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, 2003, 2004, 2005, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "hashtab.h" + +/* 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 = (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; +}; + +struct section_hash_entry +{ + struct bfd_hash_entry root; + asection section; +}; + +/* 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 */ + htab_t 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 */ + bfd_size_type extended_names_size; /* Size of extended names */ + /* 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. */ + void *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 void *bfd_malloc + (bfd_size_type); +extern void *bfd_realloc + (void *, bfd_size_type); +extern void *bfd_zmalloc + (bfd_size_type); +extern void *bfd_malloc2 + (bfd_size_type, bfd_size_type); +extern void *bfd_realloc2 + (void *, bfd_size_type, bfd_size_type); +extern void *bfd_zmalloc2 + (bfd_size_type, bfd_size_type); + +extern void _bfd_default_error_handler (const char *s, ...); +extern bfd_error_handler_type _bfd_error_handler; + +/* These routines allocate and free things on the BFD's objalloc. */ + +extern void *bfd_alloc + (bfd *, bfd_size_type); +extern void *bfd_zalloc + (bfd *, bfd_size_type); +extern void *bfd_alloc2 + (bfd *, bfd_size_type, bfd_size_type); +extern void *bfd_zalloc2 + (bfd *, bfd_size_type, bfd_size_type); +extern void bfd_release + (bfd *, void *); + +bfd * _bfd_create_empty_archive_element_shell + (bfd *obfd); +bfd * _bfd_look_for_bfd_in_cache + (bfd *, file_ptr); +bfd_boolean _bfd_add_bfd_to_archive_cache + (bfd *, file_ptr, bfd *); +bfd_boolean _bfd_generic_mkarchive + (bfd *abfd); +const bfd_target *bfd_generic_archive_p + (bfd *abfd); +bfd_boolean bfd_slurp_armap + (bfd *abfd); +bfd_boolean bfd_slurp_bsd_armap_f2 + (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 + (bfd *abfd); +extern bfd_boolean _bfd_construct_extended_name_table + (bfd *, bfd_boolean, char **, bfd_size_type *); +bfd_boolean _bfd_write_archive_contents + (bfd *abfd); +bfd_boolean _bfd_compute_and_write_armap + (bfd *, unsigned int elength); +bfd *_bfd_get_elt_at_filepos + (bfd *archive, file_ptr filepos); +extern bfd *_bfd_generic_get_elt_at_index + (bfd *, symindex); +bfd * _bfd_new_bfd + (void); +void _bfd_delete_bfd + (bfd *); + +bfd_boolean bfd_false + (bfd *ignore); +bfd_boolean bfd_true + (bfd *ignore); +void *bfd_nullvoidptr + (bfd *ignore); +int bfd_0 + (bfd *ignore); +unsigned int bfd_0u + (bfd *ignore); +long bfd_0l + (bfd *ignore); +long _bfd_n1 + (bfd *ignore); +void bfd_void + (bfd *ignore); + +bfd *_bfd_new_bfd_contained_in + (bfd *); +const bfd_target *_bfd_dummy_target + (bfd *abfd); + +void bfd_dont_truncate_arname + (bfd *abfd, const char *filename, char *hdr); +void bfd_bsd_truncate_arname + (bfd *abfd, const char *filename, char *hdr); +void bfd_gnu_truncate_arname + (bfd *abfd, const char *filename, char *hdr); + +bfd_boolean bsd_write_armap + (bfd *arch, unsigned int elength, struct orl *map, unsigned int orl_count, + int stridx); + +bfd_boolean coff_write_armap + (bfd *arch, unsigned int elength, struct orl *map, unsigned int orl_count, + int stridx); + +extern void *_bfd_generic_read_ar_hdr + (bfd *); +extern void _bfd_ar_spacepad + (char *, size_t, const char *, long); + +extern void *_bfd_generic_read_ar_hdr_mag + (bfd *, const char *); + +bfd * bfd_generic_openr_next_archived_file + (bfd *archive, bfd *last_file); + +int bfd_generic_stat_arch_elt + (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 (*) (bfd *, asection *)) bfd_true) +extern bfd_boolean _bfd_generic_get_section_contents + (bfd *, asection *, void *, file_ptr, bfd_size_type); +extern bfd_boolean _bfd_generic_get_section_contents_in_window + (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 (*) (bfd *, bfd *)) bfd_true) +#define _bfd_generic_bfd_merge_private_bfd_data \ + ((bfd_boolean (*) (bfd *, bfd *)) bfd_true) +#define _bfd_generic_bfd_set_private_flags \ + ((bfd_boolean (*) (bfd *, flagword)) bfd_true) +#define _bfd_generic_bfd_copy_private_section_data \ + ((bfd_boolean (*) (bfd *, asection *, bfd *, asection *)) bfd_true) +#define _bfd_generic_bfd_copy_private_symbol_data \ + ((bfd_boolean (*) (bfd *, asymbol *, bfd *, asymbol *)) bfd_true) +#define _bfd_generic_bfd_copy_private_header_data \ + ((bfd_boolean (*) (bfd *, bfd *)) bfd_true) +#define _bfd_generic_bfd_print_private_bfd_data \ + ((bfd_boolean (*) (bfd *, void *)) bfd_true) + +extern bfd_boolean _bfd_generic_init_private_section_data + (bfd *, asection *, bfd *, asection *, struct bfd_link_info *); + +/* 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 + (bfd *); +extern int _bfd_nocore_core_file_failing_signal + (bfd *); +extern bfd_boolean _bfd_nocore_core_file_matches_executable_p + (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 (*) (bfd *, char **, bfd_size_type *, const char **)) \ + bfd_false) +#define _bfd_noarchive_truncate_arname \ + ((void (*) (bfd *, const char *, char *)) bfd_void) +#define _bfd_noarchive_write_armap \ + ((bfd_boolean (*) (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 *(*) (bfd *, bfd *)) bfd_nullvoidptr) +#define _bfd_noarchive_get_elt_at_index \ + ((bfd *(*) (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 + (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 + (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 + (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_canonicalize_symtab \ + ((long (*) (bfd *, asymbol **)) _bfd_n1) +#define _bfd_nosymbols_make_empty_symbol _bfd_generic_make_empty_symbol +#define _bfd_nosymbols_print_symbol \ + ((void (*) (bfd *, void *, asymbol *, bfd_print_symbol_type)) bfd_void) +#define _bfd_nosymbols_get_symbol_info \ + ((void (*) (bfd *, asymbol *, symbol_info *)) bfd_void) +#define _bfd_nosymbols_bfd_is_local_label_name \ + ((bfd_boolean (*) (bfd *, const char *)) bfd_false) +#define _bfd_nosymbols_bfd_is_target_special_symbol \ + ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) +#define _bfd_nosymbols_get_lineno \ + ((alent *(*) (bfd *, asymbol *)) bfd_nullvoidptr) +#define _bfd_nosymbols_find_nearest_line \ + ((bfd_boolean (*) (bfd *, asection *, asymbol **, bfd_vma, const char **, \ + const char **, unsigned int *)) \ + bfd_false) +#define _bfd_nosymbols_find_inliner_info \ + ((bfd_boolean (*) (bfd *, const char **, const char **, unsigned int *)) \ + bfd_false) +#define _bfd_nosymbols_bfd_make_debug_symbol \ + ((asymbol *(*) (bfd *, void *, unsigned long)) bfd_nullvoidptr) +#define _bfd_nosymbols_read_minisymbols \ + ((long (*) (bfd *, bfd_boolean, void **, unsigned int *)) _bfd_n1) +#define _bfd_nosymbols_minisymbol_to_symbol \ + ((asymbol *(*) (bfd *, bfd_boolean, const void *, 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 (*) (bfd *, asection *)) _bfd_n1) +#define _bfd_norelocs_canonicalize_reloc \ + ((long (*) (bfd *, asection *, arelent **, asymbol **)) _bfd_n1) +#define _bfd_norelocs_bfd_reloc_type_lookup \ + ((reloc_howto_type *(*) (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 (*) (bfd *, enum bfd_architecture, unsigned long)) \ + bfd_false) +#define _bfd_nowrite_set_section_contents \ + ((bfd_boolean (*) (bfd *, asection *, const void *, 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 + (bfd *, asection *, const void *, 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 (*) (bfd *, bfd_boolean)) bfd_0) +#define _bfd_nolink_bfd_get_relocated_section_contents \ + ((bfd_byte *(*) (bfd *, struct bfd_link_info *, struct bfd_link_order *, \ + bfd_byte *, bfd_boolean, asymbol **)) \ + bfd_nullvoidptr) +#define _bfd_nolink_bfd_relax_section \ + ((bfd_boolean (*) \ + (bfd *, asection *, struct bfd_link_info *, bfd_boolean *)) \ + bfd_false) +#define _bfd_nolink_bfd_gc_sections \ + ((bfd_boolean (*) (bfd *, struct bfd_link_info *)) \ + bfd_false) +#define _bfd_nolink_bfd_merge_sections \ + ((bfd_boolean (*) (bfd *, struct bfd_link_info *)) \ + bfd_false) +#define _bfd_nolink_bfd_is_group_section \ + ((bfd_boolean (*) (bfd *, const struct bfd_section *)) \ + bfd_false) +#define _bfd_nolink_bfd_discard_group \ + ((bfd_boolean (*) (bfd *, struct bfd_section *)) \ + bfd_false) +#define _bfd_nolink_bfd_link_hash_table_create \ + ((struct bfd_link_hash_table *(*) (bfd *)) bfd_nullvoidptr) +#define _bfd_nolink_bfd_link_hash_table_free \ + ((void (*) (struct bfd_link_hash_table *)) bfd_void) +#define _bfd_nolink_bfd_link_add_symbols \ + ((bfd_boolean (*) (bfd *, struct bfd_link_info *)) bfd_false) +#define _bfd_nolink_bfd_link_just_syms \ + ((void (*) (asection *, struct bfd_link_info *)) bfd_void) +#define _bfd_nolink_bfd_final_link \ + ((bfd_boolean (*) (bfd *, struct bfd_link_info *)) bfd_false) +#define _bfd_nolink_bfd_link_split_section \ + ((bfd_boolean (*) (bfd *, struct bfd_section *)) bfd_false) +#define _bfd_nolink_section_already_linked \ + ((void (*) (bfd *, struct bfd_section *)) bfd_void) + +/* 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 (*) (bfd *, asymbol **)) _bfd_n1) +#define _bfd_nodynamic_get_synthetic_symtab \ + ((long (*) (bfd *, long, asymbol **, long, asymbol **, asymbol **)) _bfd_n1) +#define _bfd_nodynamic_get_dynamic_reloc_upper_bound _bfd_n1 +#define _bfd_nodynamic_canonicalize_dynamic_reloc \ + ((long (*) (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 + (bfd *, const char *); + +/* Generic minisymbol routines. */ +extern long _bfd_generic_read_minisymbols + (bfd *, bfd_boolean, void **, unsigned int *); +extern asymbol *_bfd_generic_minisymbol_to_symbol + (bfd *, bfd_boolean, const void *, asymbol *); + +/* Find the nearest line using .stab/.stabstr sections. */ +extern bfd_boolean _bfd_stab_section_find_nearest_line + (bfd *, asymbol **, asection *, bfd_vma, bfd_boolean *, + const char **, const char **, unsigned int *, void **); + +/* Find the nearest line using DWARF 1 debugging information. */ +extern bfd_boolean _bfd_dwarf1_find_nearest_line + (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 + (bfd *, asection *, asymbol **, bfd_vma, const char **, const char **, + unsigned int *, unsigned int, void **); + +/* Find the line using DWARF 2 debugging information. */ +extern bfd_boolean _bfd_dwarf2_find_line + (bfd *, asymbol **, asymbol *, const char **, + unsigned int *, unsigned int, void **); + +bfd_boolean _bfd_generic_find_line + (bfd *, asymbol **, asymbol *, const char **, unsigned int *); + +/* Find inliner info after calling bfd_find_nearest_line. */ +extern bfd_boolean _bfd_dwarf2_find_inliner_info + (bfd *, const char **, const char **, unsigned int *, void **); + +/* Create a new section entry. */ +extern struct bfd_hash_entry *bfd_section_hash_newfunc + (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 + (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 + (struct bfd_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int); + +/* Generic link hash table creation routine. */ +extern struct bfd_link_hash_table *_bfd_generic_link_hash_table_create + (bfd *); + +/* Generic link hash table destruction routine. */ +extern void _bfd_generic_link_hash_table_free + (struct bfd_link_hash_table *); + +/* Generic add symbol routine. */ +extern bfd_boolean _bfd_generic_link_add_symbols + (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 + (bfd *, struct bfd_link_info *); + +/* Generic archive add symbol routine. */ +extern bfd_boolean _bfd_generic_link_add_archive_symbols + (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 + (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 + (asection *, struct bfd_link_info *); + +/* Generic link routine. */ +extern bfd_boolean _bfd_generic_final_link + (bfd *, struct bfd_link_info *); + +extern bfd_boolean _bfd_generic_link_split_section + (bfd *, struct bfd_section *); + +extern void _bfd_generic_section_already_linked + (bfd *, struct bfd_section *); + +/* Generic reloc_link_order processing routine. */ +extern bfd_boolean _bfd_generic_reloc_link_order + (bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *); + +/* Default link order processing routine. */ +extern bfd_boolean _bfd_default_link_order + (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 + (struct bfd_link_order *); + +/* Final link relocation routine. */ +extern bfd_reloc_status_type _bfd_final_link_relocate + (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 + (reloc_howto_type *, bfd *, bfd_vma, bfd_byte *); + +/* Link stabs in sections in the first pass. */ + +extern bfd_boolean _bfd_link_section_stabs + (bfd *, struct stab_info *, asection *, asection *, void **, + bfd_size_type *); + +/* Eliminate stabs for discarded functions and symbols. */ +extern bfd_boolean _bfd_discard_section_stabs + (bfd *, asection *, void *, bfd_boolean (*) (bfd_vma, void *), void *); + +/* Write out the .stab section when linking stabs in sections. */ + +extern bfd_boolean _bfd_write_section_stabs + (bfd *, struct stab_info *, asection *, void **, bfd_byte *); + +/* Write out the .stabstr string table when linking stabs in sections. */ + +extern bfd_boolean _bfd_write_stab_strings + (bfd *, struct stab_info *); + +/* Find an offset within a .stab section when linking stabs in + sections. */ + +extern bfd_vma _bfd_stab_section_offset + (asection *, void *, bfd_vma); + +/* Register a SEC_MERGE section as a candidate for merging. */ + +extern bfd_boolean _bfd_add_merge_section + (bfd *, void **, asection *, void **); + +/* Attempt to merge SEC_MERGE sections. */ + +extern bfd_boolean _bfd_merge_sections + (bfd *, struct bfd_link_info *, void *, void (*) (bfd *, asection *)); + +/* Write out a merged section. */ + +extern bfd_boolean _bfd_write_merged_section + (bfd *, asection *, void *); + +/* Find an offset within a modified SEC_MERGE section. */ + +extern bfd_vma _bfd_merged_section_offset + (bfd *, asection **, void *, bfd_vma); + +/* Create a string table. */ +extern struct bfd_strtab_hash *_bfd_stringtab_init + (void); + +/* Create an XCOFF .debug section style string table. */ +extern struct bfd_strtab_hash *_bfd_xcoff_stringtab_init + (void); + +/* Free a string table. */ +extern void _bfd_stringtab_free + (struct bfd_strtab_hash *); + +/* Get the size of a string table. */ +extern bfd_size_type _bfd_stringtab_size + (struct bfd_strtab_hash *); + +/* Add a string to a string table. */ +extern bfd_size_type _bfd_stringtab_add + (struct bfd_strtab_hash *, const char *, bfd_boolean hash, bfd_boolean copy); + +/* Write out a string table. */ +extern bfd_boolean _bfd_stringtab_emit + (bfd *, struct bfd_strtab_hash *); + +/* Check that endianness of input and output file match. */ +extern bfd_boolean _bfd_generic_verify_endian_match + (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 + (const char*,int); + +#define BFD_ASSERT(x) \ + do { if (!(x)) bfd_assert(__FILE__,__LINE__); } while (0) + +#define BFD_FAIL() \ + do { bfd_assert(__FILE__,__LINE__); } while (0) + +extern void _bfd_abort + (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__) + +/* Manipulate a system FILE but using BFD's "file_ptr", rather than + the system "off_t" or "off64_t", as the offset. */ +extern file_ptr real_ftell (FILE *file); +extern int real_fseek (FILE *file, file_ptr offset, int whence); +extern FILE *real_fopen (const char *filename, const char *modes); + +/* 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 + (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 + (void *, bfd_byte *); +extern bfd_boolean _bfd_ecoff_get_accumulated_sym + (void *, bfd_byte *); +extern bfd_boolean _bfd_ecoff_get_accumulated_ss + (void *, bfd_byte *); + +extern bfd_vma _bfd_get_gp_value + (bfd *); +extern void _bfd_set_gp_value + (bfd *, bfd_vma); + +/* Function shared by the COFF and ELF SH backends, which have no + other common header files. */ + +#ifndef _bfd_sh_align_load_span +extern bfd_boolean _bfd_sh_align_load_span + (bfd *, asection *, bfd_byte *, + bfd_boolean (*) (bfd *, asection *, void *, bfd_byte *, bfd_vma), + void *, bfd_vma **, bfd_vma *, bfd_vma, bfd_vma, bfd_boolean *); +#endif + +/* 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. */ + +struct bfd_section_already_linked_hash_entry +{ + struct bfd_hash_entry root; + struct bfd_section_already_linked *entry; +}; + +struct bfd_section_already_linked +{ + struct bfd_section_already_linked *next; + asection *sec; +}; + +extern struct bfd_section_already_linked_hash_entry * + bfd_section_already_linked_table_lookup (const char *); +extern void bfd_section_already_linked_table_insert + (struct bfd_section_already_linked_hash_entry *, asection *); +extern void bfd_section_already_linked_table_traverse + (bfd_boolean (*) (struct bfd_section_already_linked_hash_entry *, + void *), void *); + +extern bfd_vma read_unsigned_leb128 (bfd *, bfd_byte *, unsigned int *); +extern bfd_signed_vma read_signed_leb128 (bfd *, bfd_byte *, unsigned int *); + +/* Extracted from init.c. */ +/* Extracted from libbfd.c. */ +bfd_boolean bfd_write_bigendian_4byte_int (bfd *, unsigned int); + +unsigned int bfd_log2 (bfd_vma x); + +/* Extracted from bfdio.c. */ +struct bfd_iovec +{ + /* To avoid problems with macros, a "b" rather than "f" + prefix is prepended to each method name. */ + /* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching + bytes starting at PTR. Return the number of bytes actually + transfered (a read past end-of-file returns less than NBYTES), + or -1 (setting <>) if an error occurs. */ + file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes); + file_ptr (*bwrite) (struct bfd *abfd, const void *ptr, + file_ptr nbytes); + /* Return the current IOSTREAM file offset, or -1 (setting <> + if an error occurs. */ + file_ptr (*btell) (struct bfd *abfd); + /* For the following, on successful completion a value of 0 is returned. + Otherwise, a value of -1 is returned (and <> is set). */ + int (*bseek) (struct bfd *abfd, file_ptr offset, int whence); + int (*bclose) (struct bfd *abfd); + int (*bflush) (struct bfd *abfd); + int (*bstat) (struct bfd *abfd, struct stat *sb); +}; +/* Extracted from bfdwin.c. */ +struct _bfd_window_internal { + struct _bfd_window_internal *next; + void *data; + bfd_size_type size; + int refcount : 31; /* should be enough... */ + unsigned mapped : 1; /* 1 = mmap, 0 = malloc */ +}; +/* Extracted from cache.c. */ +bfd_boolean bfd_cache_init (bfd *abfd); + +bfd_boolean bfd_cache_close (bfd *abfd); + +FILE* bfd_open_file (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_SECREL", + "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_HI16_PCREL", + "BFD_RELOC_HI16_S_PCREL", + "BFD_RELOC_LO16_PCREL", + "BFD_RELOC_MIPS16_HI16", + "BFD_RELOC_MIPS16_HI16_S", + "BFD_RELOC_MIPS16_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_MIPS_TLS_DTPMOD32", + "BFD_RELOC_MIPS_TLS_DTPREL32", + "BFD_RELOC_MIPS_TLS_DTPMOD64", + "BFD_RELOC_MIPS_TLS_DTPREL64", + "BFD_RELOC_MIPS_TLS_GD", + "BFD_RELOC_MIPS_TLS_LDM", + "BFD_RELOC_MIPS_TLS_DTPREL_HI16", + "BFD_RELOC_MIPS_TLS_DTPREL_LO16", + "BFD_RELOC_MIPS_TLS_GOTTPREL", + "BFD_RELOC_MIPS_TLS_TPREL32", + "BFD_RELOC_MIPS_TLS_TPREL64", + "BFD_RELOC_MIPS_TLS_TPREL_HI16", + "BFD_RELOC_MIPS_TLS_TPREL_LO16", + + "BFD_RELOC_MIPS_COPY", + "BFD_RELOC_MIPS_JUMP_SLOT", + + "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_FRV_GOT12", + "BFD_RELOC_FRV_GOTHI", + "BFD_RELOC_FRV_GOTLO", + "BFD_RELOC_FRV_FUNCDESC", + "BFD_RELOC_FRV_FUNCDESC_GOT12", + "BFD_RELOC_FRV_FUNCDESC_GOTHI", + "BFD_RELOC_FRV_FUNCDESC_GOTLO", + "BFD_RELOC_FRV_FUNCDESC_VALUE", + "BFD_RELOC_FRV_FUNCDESC_GOTOFF12", + "BFD_RELOC_FRV_FUNCDESC_GOTOFFHI", + "BFD_RELOC_FRV_FUNCDESC_GOTOFFLO", + "BFD_RELOC_FRV_GOTOFF12", + "BFD_RELOC_FRV_GOTOFFHI", + "BFD_RELOC_FRV_GOTOFFLO", + "BFD_RELOC_FRV_GETTLSOFF", + "BFD_RELOC_FRV_TLSDESC_VALUE", + "BFD_RELOC_FRV_GOTTLSDESC12", + "BFD_RELOC_FRV_GOTTLSDESCHI", + "BFD_RELOC_FRV_GOTTLSDESCLO", + "BFD_RELOC_FRV_TLSMOFF12", + "BFD_RELOC_FRV_TLSMOFFHI", + "BFD_RELOC_FRV_TLSMOFFLO", + "BFD_RELOC_FRV_GOTTLSOFF12", + "BFD_RELOC_FRV_GOTTLSOFFHI", + "BFD_RELOC_FRV_GOTTLSOFFLO", + "BFD_RELOC_FRV_TLSOFF", + "BFD_RELOC_FRV_TLSDESC_RELAX", + "BFD_RELOC_FRV_GETTLSOFF_RELAX", + "BFD_RELOC_FRV_TLSOFF_RELAX", + "BFD_RELOC_FRV_TLSMOFF", + + "BFD_RELOC_MN10300_GOTOFF24", + "BFD_RELOC_MN10300_GOT32", + "BFD_RELOC_MN10300_GOT24", + "BFD_RELOC_MN10300_GOT16", + "BFD_RELOC_MN10300_COPY", + "BFD_RELOC_MN10300_GLOB_DAT", + "BFD_RELOC_MN10300_JMP_SLOT", + "BFD_RELOC_MN10300_RELATIVE", + + "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_386_TLS_GOTDESC", + "BFD_RELOC_386_TLS_DESC_CALL", + "BFD_RELOC_386_TLS_DESC", + "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_X86_64_GOTOFF64", + "BFD_RELOC_X86_64_GOTPC32", + "BFD_RELOC_X86_64_GOT64", + "BFD_RELOC_X86_64_GOTPCREL64", + "BFD_RELOC_X86_64_GOTPC64", + "BFD_RELOC_X86_64_GOTPLT64", + "BFD_RELOC_X86_64_PLTOFF64", + "BFD_RELOC_X86_64_GOTPC32_TLSDESC", + "BFD_RELOC_X86_64_TLSDESC_CALL", + "BFD_RELOC_X86_64_TLSDESC", + "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_PCREL_CALL", + "BFD_RELOC_ARM_PCREL_JUMP", + "BFD_RELOC_THUMB_PCREL_BRANCH7", + "BFD_RELOC_THUMB_PCREL_BRANCH9", + "BFD_RELOC_THUMB_PCREL_BRANCH12", + "BFD_RELOC_THUMB_PCREL_BRANCH20", + "BFD_RELOC_THUMB_PCREL_BRANCH23", + "BFD_RELOC_THUMB_PCREL_BRANCH25", + "BFD_RELOC_ARM_OFFSET_IMM", + "BFD_RELOC_ARM_THUMB_OFFSET", + "BFD_RELOC_ARM_TARGET1", + "BFD_RELOC_ARM_ROSEGREL32", + "BFD_RELOC_ARM_SBREL32", + "BFD_RELOC_ARM_TARGET2", + "BFD_RELOC_ARM_PREL31", + "BFD_RELOC_ARM_JUMP_SLOT", + "BFD_RELOC_ARM_GLOB_DAT", + "BFD_RELOC_ARM_GOT32", + "BFD_RELOC_ARM_PLT32", + "BFD_RELOC_ARM_RELATIVE", + "BFD_RELOC_ARM_GOTOFF", + "BFD_RELOC_ARM_GOTPC", + "BFD_RELOC_ARM_TLS_GD32", + "BFD_RELOC_ARM_TLS_LDO32", + "BFD_RELOC_ARM_TLS_LDM32", + "BFD_RELOC_ARM_TLS_DTPOFF32", + "BFD_RELOC_ARM_TLS_DTPMOD32", + "BFD_RELOC_ARM_TLS_TPOFF32", + "BFD_RELOC_ARM_TLS_IE32", + "BFD_RELOC_ARM_TLS_LE32", + "BFD_RELOC_ARM_IMMEDIATE", + "BFD_RELOC_ARM_ADRL_IMMEDIATE", + "BFD_RELOC_ARM_T32_IMMEDIATE", + "BFD_RELOC_ARM_T32_IMM12", + "BFD_RELOC_ARM_T32_ADD_PC12", + "BFD_RELOC_ARM_SHIFT_IMM", + "BFD_RELOC_ARM_SMC", + "BFD_RELOC_ARM_SWI", + "BFD_RELOC_ARM_MULTI", + "BFD_RELOC_ARM_CP_OFF_IMM", + "BFD_RELOC_ARM_CP_OFF_IMM_S2", + "BFD_RELOC_ARM_T32_CP_OFF_IMM", + "BFD_RELOC_ARM_T32_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_T32_OFFSET_U8", + "BFD_RELOC_ARM_T32_OFFSET_IMM", + "BFD_RELOC_ARM_HWLITERAL", + "BFD_RELOC_ARM_THUMB_ADD", + "BFD_RELOC_ARM_THUMB_IMM", + "BFD_RELOC_ARM_THUMB_SHIFT", + "BFD_RELOC_SH_PCDISP8BY2", + "BFD_RELOC_SH_PCDISP12BY2", + "BFD_RELOC_SH_IMM3", + "BFD_RELOC_SH_IMM3U", + "BFD_RELOC_SH_DISP12", + "BFD_RELOC_SH_DISP12BY2", + "BFD_RELOC_SH_DISP12BY4", + "BFD_RELOC_SH_DISP12BY8", + "BFD_RELOC_SH_DISP20", + "BFD_RELOC_SH_DISP20BY8", + "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_ARC_B22_PCREL", + "BFD_RELOC_ARC_B26", + "BFD_RELOC_BFIN_16_IMM", + "BFD_RELOC_BFIN_16_HIGH", + "BFD_RELOC_BFIN_4_PCREL", + "BFD_RELOC_BFIN_5_PCREL", + "BFD_RELOC_BFIN_16_LOW", + "BFD_RELOC_BFIN_10_PCREL", + "BFD_RELOC_BFIN_11_PCREL", + "BFD_RELOC_BFIN_12_PCREL_JUMP", + "BFD_RELOC_BFIN_12_PCREL_JUMP_S", + "BFD_RELOC_BFIN_24_PCREL_CALL_X", + "BFD_RELOC_BFIN_24_PCREL_JUMP_L", + "BFD_RELOC_BFIN_GOT17M4", + "BFD_RELOC_BFIN_GOTHI", + "BFD_RELOC_BFIN_GOTLO", + "BFD_RELOC_BFIN_FUNCDESC", + "BFD_RELOC_BFIN_FUNCDESC_GOT17M4", + "BFD_RELOC_BFIN_FUNCDESC_GOTHI", + "BFD_RELOC_BFIN_FUNCDESC_GOTLO", + "BFD_RELOC_BFIN_FUNCDESC_VALUE", + "BFD_RELOC_BFIN_FUNCDESC_GOTOFF17M4", + "BFD_RELOC_BFIN_FUNCDESC_GOTOFFHI", + "BFD_RELOC_BFIN_FUNCDESC_GOTOFFLO", + "BFD_RELOC_BFIN_GOTOFF17M4", + "BFD_RELOC_BFIN_GOTOFFHI", + "BFD_RELOC_BFIN_GOTOFFLO", + "BFD_RELOC_BFIN_GOT", + "BFD_RELOC_BFIN_PLTPC", + "BFD_ARELOC_BFIN_PUSH", + "BFD_ARELOC_BFIN_CONST", + "BFD_ARELOC_BFIN_ADD", + "BFD_ARELOC_BFIN_SUB", + "BFD_ARELOC_BFIN_MULT", + "BFD_ARELOC_BFIN_DIV", + "BFD_ARELOC_BFIN_MOD", + "BFD_ARELOC_BFIN_LSHIFT", + "BFD_ARELOC_BFIN_RSHIFT", + "BFD_ARELOC_BFIN_AND", + "BFD_ARELOC_BFIN_OR", + "BFD_ARELOC_BFIN_XOR", + "BFD_ARELOC_BFIN_LAND", + "BFD_ARELOC_BFIN_LOR", + "BFD_ARELOC_BFIN_LEN", + "BFD_ARELOC_BFIN_NEG", + "BFD_ARELOC_BFIN_COMP", + "BFD_ARELOC_BFIN_PAGE", + "BFD_ARELOC_BFIN_HWPAGE", + "BFD_ARELOC_BFIN_ADDR", + "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_M32C_HI8", + "BFD_RELOC_M32C_RL_JUMP", + "BFD_RELOC_M32C_RL_1ADDR", + "BFD_RELOC_M32C_RL_2ADDR", + "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_M32R_GOT24", + "BFD_RELOC_M32R_26_PLTREL", + "BFD_RELOC_M32R_COPY", + "BFD_RELOC_M32R_GLOB_DAT", + "BFD_RELOC_M32R_JMP_SLOT", + "BFD_RELOC_M32R_RELATIVE", + "BFD_RELOC_M32R_GOTOFF", + "BFD_RELOC_M32R_GOTOFF_HI_ULO", + "BFD_RELOC_M32R_GOTOFF_HI_SLO", + "BFD_RELOC_M32R_GOTOFF_LO", + "BFD_RELOC_M32R_GOTPC24", + "BFD_RELOC_M32R_GOT16_HI_ULO", + "BFD_RELOC_M32R_GOT16_HI_SLO", + "BFD_RELOC_M32R_GOT16_LO", + "BFD_RELOC_M32R_GOTPC_HI_ULO", + "BFD_RELOC_M32R_GOTPC_HI_SLO", + "BFD_RELOC_M32R_GOTPC_LO", + "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_V850_LO16_SPLIT_OFFSET", + "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_PUSHJ_STUBBABLE", + "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_MS8_LDI", + "BFD_RELOC_AVR_LO8_LDI_NEG", + "BFD_RELOC_AVR_HI8_LDI_NEG", + "BFD_RELOC_AVR_HH8_LDI_NEG", + "BFD_RELOC_AVR_MS8_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_AVR_LDI", + "BFD_RELOC_AVR_6", + "BFD_RELOC_AVR_6_ADIW", + "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_390_20", + "BFD_RELOC_390_GOT20", + "BFD_RELOC_390_GOTPLT20", + "BFD_RELOC_390_TLS_GOTIE20", + "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_M68HC12_5B", + "BFD_RELOC_16C_NUM08", + "BFD_RELOC_16C_NUM08_C", + "BFD_RELOC_16C_NUM16", + "BFD_RELOC_16C_NUM16_C", + "BFD_RELOC_16C_NUM32", + "BFD_RELOC_16C_NUM32_C", + "BFD_RELOC_16C_DISP04", + "BFD_RELOC_16C_DISP04_C", + "BFD_RELOC_16C_DISP08", + "BFD_RELOC_16C_DISP08_C", + "BFD_RELOC_16C_DISP16", + "BFD_RELOC_16C_DISP16_C", + "BFD_RELOC_16C_DISP24", + "BFD_RELOC_16C_DISP24_C", + "BFD_RELOC_16C_DISP24a", + "BFD_RELOC_16C_DISP24a_C", + "BFD_RELOC_16C_REG04", + "BFD_RELOC_16C_REG04_C", + "BFD_RELOC_16C_REG04a", + "BFD_RELOC_16C_REG04a_C", + "BFD_RELOC_16C_REG14", + "BFD_RELOC_16C_REG14_C", + "BFD_RELOC_16C_REG16", + "BFD_RELOC_16C_REG16_C", + "BFD_RELOC_16C_REG20", + "BFD_RELOC_16C_REG20_C", + "BFD_RELOC_16C_ABS20", + "BFD_RELOC_16C_ABS20_C", + "BFD_RELOC_16C_ABS24", + "BFD_RELOC_16C_ABS24_C", + "BFD_RELOC_16C_IMM04", + "BFD_RELOC_16C_IMM04_C", + "BFD_RELOC_16C_IMM16", + "BFD_RELOC_16C_IMM16_C", + "BFD_RELOC_16C_IMM20", + "BFD_RELOC_16C_IMM20_C", + "BFD_RELOC_16C_IMM24", + "BFD_RELOC_16C_IMM24_C", + "BFD_RELOC_16C_IMM32", + "BFD_RELOC_16C_IMM32_C", + "BFD_RELOC_CRX_REL4", + "BFD_RELOC_CRX_REL8", + "BFD_RELOC_CRX_REL8_CMP", + "BFD_RELOC_CRX_REL16", + "BFD_RELOC_CRX_REL24", + "BFD_RELOC_CRX_REL32", + "BFD_RELOC_CRX_REGREL12", + "BFD_RELOC_CRX_REGREL22", + "BFD_RELOC_CRX_REGREL28", + "BFD_RELOC_CRX_REGREL32", + "BFD_RELOC_CRX_ABS16", + "BFD_RELOC_CRX_ABS32", + "BFD_RELOC_CRX_NUM8", + "BFD_RELOC_CRX_NUM16", + "BFD_RELOC_CRX_NUM32", + "BFD_RELOC_CRX_IMM16", + "BFD_RELOC_CRX_IMM32", + "BFD_RELOC_CRX_SWITCH8", + "BFD_RELOC_CRX_SWITCH16", + "BFD_RELOC_CRX_SWITCH32", + "BFD_RELOC_CRIS_BDISP8", + "BFD_RELOC_CRIS_UNSIGNED_5", + "BFD_RELOC_CRIS_SIGNED_6", + "BFD_RELOC_CRIS_UNSIGNED_6", + "BFD_RELOC_CRIS_SIGNED_8", + "BFD_RELOC_CRIS_UNSIGNED_8", + "BFD_RELOC_CRIS_SIGNED_16", + "BFD_RELOC_CRIS_UNSIGNED_16", + "BFD_RELOC_CRIS_LAPCQ_OFFSET", + "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_XC16X_PAG", + "BFD_RELOC_XC16X_POF", + "BFD_RELOC_XC16X_SEG", + "BFD_RELOC_XC16X_SOF", + "BFD_RELOC_VAX_GLOB_DAT", + "BFD_RELOC_VAX_JMP_SLOT", + "BFD_RELOC_VAX_RELATIVE", + "BFD_RELOC_MT_PC16", + "BFD_RELOC_MT_HI16", + "BFD_RELOC_MT_LO16", + "BFD_RELOC_MT_GNU_VTINHERIT", + "BFD_RELOC_MT_GNU_VTENTRY", + "BFD_RELOC_MT_PCINSN8", + "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_MSP430_2X_PCREL", + "BFD_RELOC_MSP430_RL_PCREL", + "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_DIFF8", + "BFD_RELOC_XTENSA_DIFF16", + "BFD_RELOC_XTENSA_DIFF32", + "BFD_RELOC_XTENSA_SLOT0_OP", + "BFD_RELOC_XTENSA_SLOT1_OP", + "BFD_RELOC_XTENSA_SLOT2_OP", + "BFD_RELOC_XTENSA_SLOT3_OP", + "BFD_RELOC_XTENSA_SLOT4_OP", + "BFD_RELOC_XTENSA_SLOT5_OP", + "BFD_RELOC_XTENSA_SLOT6_OP", + "BFD_RELOC_XTENSA_SLOT7_OP", + "BFD_RELOC_XTENSA_SLOT8_OP", + "BFD_RELOC_XTENSA_SLOT9_OP", + "BFD_RELOC_XTENSA_SLOT10_OP", + "BFD_RELOC_XTENSA_SLOT11_OP", + "BFD_RELOC_XTENSA_SLOT12_OP", + "BFD_RELOC_XTENSA_SLOT13_OP", + "BFD_RELOC_XTENSA_SLOT14_OP", + "BFD_RELOC_XTENSA_SLOT0_ALT", + "BFD_RELOC_XTENSA_SLOT1_ALT", + "BFD_RELOC_XTENSA_SLOT2_ALT", + "BFD_RELOC_XTENSA_SLOT3_ALT", + "BFD_RELOC_XTENSA_SLOT4_ALT", + "BFD_RELOC_XTENSA_SLOT5_ALT", + "BFD_RELOC_XTENSA_SLOT6_ALT", + "BFD_RELOC_XTENSA_SLOT7_ALT", + "BFD_RELOC_XTENSA_SLOT8_ALT", + "BFD_RELOC_XTENSA_SLOT9_ALT", + "BFD_RELOC_XTENSA_SLOT10_ALT", + "BFD_RELOC_XTENSA_SLOT11_ALT", + "BFD_RELOC_XTENSA_SLOT12_ALT", + "BFD_RELOC_XTENSA_SLOT13_ALT", + "BFD_RELOC_XTENSA_SLOT14_ALT", + "BFD_RELOC_XTENSA_OP0", + "BFD_RELOC_XTENSA_OP1", + "BFD_RELOC_XTENSA_OP2", + "BFD_RELOC_XTENSA_ASM_EXPAND", + "BFD_RELOC_XTENSA_ASM_SIMPLIFY", + "BFD_RELOC_Z80_DISP8", + "BFD_RELOC_Z8K_DISP7", + "BFD_RELOC_Z8K_CALLR", + "BFD_RELOC_Z8K_IMM4L", + "@@overflow: BFD_RELOC_UNUSED@@", +}; +#endif + +reloc_howto_type *bfd_default_reloc_type_lookup + (bfd *abfd, bfd_reloc_code_real_type code); + +bfd_boolean bfd_generic_relax_section + (bfd *abfd, + asection *section, + struct bfd_link_info *, + bfd_boolean *); + +bfd_boolean bfd_generic_gc_sections + (bfd *, struct bfd_link_info *); + +bfd_boolean bfd_generic_merge_sections + (bfd *, struct bfd_link_info *); + +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 relocatable, + asymbol **symbols); + +/* Extracted from archures.c. */ +extern const bfd_arch_info_type bfd_default_arch_struct; +bfd_boolean bfd_default_set_arch_mach + (bfd *abfd, enum bfd_architecture arch, unsigned long mach); + +const bfd_arch_info_type *bfd_default_compatible + (const bfd_arch_info_type *a, const bfd_arch_info_type *b); + +bfd_boolean bfd_default_scan + (const struct bfd_arch_info *info, const char *string); + +/* Extracted from elf.c. */ +struct elf_internal_shdr *bfd_elf_find_section (bfd *abfd, char *name); + diff --git a/contrib/binutils-2.17/bfd/libcoff.h b/contrib/binutils-2.17/bfd/libcoff.h new file mode 100644 index 0000000000..f756f30b1b --- /dev/null +++ b/contrib/binutils-2.17/bfd/libcoff.h @@ -0,0 +1,935 @@ +/* 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, 2003, 2004, 2005, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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. */ + void * 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. */ + void * line_info; + + /* A place to stash dwarf2 info for this bfd. */ + void * 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) (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; + /* Optional information about a COMDAT entry; NULL if not COMDAT. */ + struct coff_comdat_info *comdat; + int line_base; + /* A pointer used for .stab linking optimizations. */ + void * stab_info; + /* Available for individual backends. */ + void * tdata; +}; + +/* An accessor macro for the coff_section_tdata structure. */ +#define coff_section_data(abfd, sec) \ + ((struct coff_section_tdata *) (sec)->used_by_bfd) + +/* 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. */ + struct stab_info 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 (*) (struct bfd_link_hash_entry *, void *)) (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 + (bfd *); +extern struct bfd_section *coff_section_from_bfd_index + (bfd *, int); +extern long coff_get_symtab_upper_bound + (bfd *); +extern long coff_canonicalize_symtab + (bfd *, asymbol **); +extern int coff_count_linenumbers + (bfd *); +extern struct coff_symbol_struct *coff_symbol_from + (bfd *, asymbol *); +extern bfd_boolean coff_renumber_symbols + (bfd *, int *); +extern void coff_mangle_symbols + (bfd *); +extern bfd_boolean coff_write_symbols + (bfd *); +extern bfd_boolean coff_write_linenumbers + (bfd *); +extern alent *coff_get_lineno + (bfd *, asymbol *); +extern asymbol *coff_section_symbol + (bfd *, char *); +extern bfd_boolean _bfd_coff_get_external_symbols + (bfd *); +extern const char *_bfd_coff_read_string_table + (bfd *); +extern bfd_boolean _bfd_coff_free_symbols + (bfd *); +extern struct coff_ptr_struct *coff_get_normalized_symtab + (bfd *); +extern long coff_get_reloc_upper_bound + (bfd *, sec_ptr); +extern asymbol *coff_make_empty_symbol + (bfd *); +extern void coff_print_symbol + (bfd *, void * filep, asymbol *, bfd_print_symbol_type); +extern void coff_get_symbol_info + (bfd *, asymbol *, symbol_info *ret); +extern bfd_boolean _bfd_coff_is_local_label_name + (bfd *, const char *); +extern asymbol *coff_bfd_make_debug_symbol + (bfd *, void *, unsigned long); +extern bfd_boolean coff_find_nearest_line + (bfd *, asection *, asymbol **, bfd_vma, const char **, + const char **, unsigned int *); +extern bfd_boolean coff_find_inliner_info + (bfd *, const char **, const char **, unsigned int *); +extern int coff_sizeof_headers + (bfd *, bfd_boolean); +extern bfd_boolean bfd_coff_reloc16_relax_section + (bfd *, asection *, struct bfd_link_info *, bfd_boolean *); +extern bfd_byte *bfd_coff_reloc16_get_relocated_section_contents + (bfd *, struct bfd_link_info *, struct bfd_link_order *, + bfd_byte *, bfd_boolean, asymbol **); +extern bfd_vma bfd_coff_reloc16_get_value + (arelent *, struct bfd_link_info *, asection *); +extern void bfd_perform_slip + (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, \ + sizeof (struct coff_debug_merge_hash_entry))) + +/* 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 relocatable 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 relocatable 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 + (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); +extern bfd_boolean _bfd_coff_link_hash_table_init + (struct coff_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int); +extern struct bfd_link_hash_table *_bfd_coff_link_hash_table_create + (bfd *); +extern const char *_bfd_coff_internal_syment_name + (bfd *, const struct internal_syment *, char *); +extern bfd_boolean _bfd_coff_link_add_symbols + (bfd *, struct bfd_link_info *); +extern bfd_boolean _bfd_coff_final_link + (bfd *, struct bfd_link_info *); +extern struct internal_reloc *_bfd_coff_read_internal_relocs + (bfd *, asection *, bfd_boolean, bfd_byte *, bfd_boolean, + struct internal_reloc *); +extern bfd_boolean _bfd_coff_generic_relocate_section + (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 + (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); +extern bfd_boolean _bfd_coff_write_global_sym + (struct coff_link_hash_entry *, void *); +extern bfd_boolean _bfd_coff_write_task_globals + (struct coff_link_hash_entry *, void *); +extern bfd_boolean _bfd_coff_link_input_bfd + (struct coff_final_link_info *, bfd *); +extern bfd_boolean _bfd_coff_reloc_link_order + (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 + (bfd *); +extern long _bfd_xcoff_canonicalize_dynamic_symtab + (bfd *, asymbol **); +extern long _bfd_xcoff_get_dynamic_reloc_upper_bound + (bfd *); +extern long _bfd_xcoff_canonicalize_dynamic_reloc + (bfd *, arelent **, asymbol **); +extern struct bfd_link_hash_table *_bfd_xcoff_bfd_link_hash_table_create + (bfd *); +extern void _bfd_xcoff_bfd_link_hash_table_free + (struct bfd_link_hash_table *); +extern bfd_boolean _bfd_xcoff_bfd_link_add_symbols + (bfd *, struct bfd_link_info *); +extern bfd_boolean _bfd_xcoff_bfd_final_link + (bfd *, struct bfd_link_info *); +extern bfd_boolean _bfd_ppc_xcoff_relocate_section + (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 + (struct bfd_link_info *); +extern bfd_boolean ppc_process_before_allocation + (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) + (bfd *, void *, int, int, int, int, void *); + + void (*_bfd_coff_swap_sym_in) + (bfd *, void *, void *); + + void (*_bfd_coff_swap_lineno_in) + (bfd *, void *, void *); + + unsigned int (*_bfd_coff_swap_aux_out) + (bfd *, void *, int, int, int, int, void *); + + unsigned int (*_bfd_coff_swap_sym_out) + (bfd *, void *, void *); + + unsigned int (*_bfd_coff_swap_lineno_out) + (bfd *, void *, void *); + + unsigned int (*_bfd_coff_swap_reloc_out) + (bfd *, void *, void *); + + unsigned int (*_bfd_coff_swap_filehdr_out) + (bfd *, void *, void *); + + unsigned int (*_bfd_coff_swap_aouthdr_out) + (bfd *, void *, void *); + + unsigned int (*_bfd_coff_swap_scnhdr_out) + (bfd *, void *, void *); + + 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) + (bfd *, void *, void *); + + void (*_bfd_coff_swap_aouthdr_in) + (bfd *, void *, void *); + + void (*_bfd_coff_swap_scnhdr_in) + (bfd *, void *, void *); + + void (*_bfd_coff_swap_reloc_in) + (bfd *abfd, void *, void *); + + bfd_boolean (*_bfd_coff_bad_format_hook) + (bfd *, void *); + + bfd_boolean (*_bfd_coff_set_arch_mach_hook) + (bfd *, void *); + + void * (*_bfd_coff_mkobject_hook) + (bfd *, void *, void *); + + bfd_boolean (*_bfd_styp_to_sec_flags_hook) + (bfd *, void *, const char *, asection *, flagword *); + + void (*_bfd_set_alignment_hook) + (bfd *, asection *, void *); + + bfd_boolean (*_bfd_coff_slurp_symbol_table) + (bfd *); + + bfd_boolean (*_bfd_coff_symname_in_debug) + (bfd *, struct internal_syment *); + + bfd_boolean (*_bfd_coff_pointerize_aux_hook) + (bfd *, combined_entry_type *, combined_entry_type *, + unsigned int, combined_entry_type *); + + bfd_boolean (*_bfd_coff_print_aux) + (bfd *, FILE *, combined_entry_type *, combined_entry_type *, + combined_entry_type *, unsigned int); + + void (*_bfd_coff_reloc16_extra_cases) + (bfd *, struct bfd_link_info *, struct bfd_link_order *, arelent *, + bfd_byte *, unsigned int *, unsigned int *); + + int (*_bfd_coff_reloc16_estimate) + (bfd *, asection *, arelent *, unsigned int, + struct bfd_link_info *); + + enum coff_symbol_classification (*_bfd_coff_classify_symbol) + (bfd *, struct internal_syment *); + + bfd_boolean (*_bfd_coff_compute_section_file_positions) + (bfd *); + + bfd_boolean (*_bfd_coff_start_final_link) + (bfd *, struct bfd_link_info *); + + bfd_boolean (*_bfd_coff_relocate_section) + (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + struct internal_reloc *, struct internal_syment *, asection **); + + reloc_howto_type *(*_bfd_coff_rtype_to_howto) + (bfd *, asection *, struct internal_reloc *, + struct coff_link_hash_entry *, struct internal_syment *, + bfd_vma *); + + bfd_boolean (*_bfd_coff_adjust_symndx) + (bfd *, struct bfd_link_info *, bfd *, asection *, + struct internal_reloc *, bfd_boolean *); + + bfd_boolean (*_bfd_coff_link_add_one_symbol) + (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) + (bfd *, struct coff_final_link_info *); + + bfd_boolean (*_bfd_coff_final_link_postscript) + (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.17/bfd/libecoff.h b/contrib/binutils-2.17/bfd/libecoff.h new file mode 100644 index 0000000000..8c5e218ee5 --- /dev/null +++ b/contrib/binutils-2.17/bfd/libecoff.h @@ -0,0 +1,337 @@ +/* BFD ECOFF object file private structure. + Copyright 1993, 1994, 1995, 1996, 1999, 2001, 2002, 2003, 2004, + 2005 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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) (bfd *, void *, struct internal_reloc *); + void (*swap_reloc_out) (bfd *, const struct internal_reloc *, void *); + /* Backend reloc tweaking. */ + void (*adjust_reloc_in) + (bfd *, const struct internal_reloc *, arelent *); + void (*adjust_reloc_out) + (bfd *, const arelent *, struct internal_reloc *); + /* Relocate section contents while linking. */ + bfd_boolean (*relocate_section) + (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, void *); + /* Do final adjustments to filehdr and aouthdr. */ + bfd_boolean (*adjust_headers) + (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) (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. */ + void * 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. */ + void * 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)) + +/* A pointer to this structure is put in the used_by_bfd pointer of + a section to keep track of any per-section data. + The user_by_bfd pointer will be NULL if the information was not + needed. */ + +struct ecoff_section_tdata +{ + /* 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 (bfd *); + +/* Read in the ECOFF symbolic debugging information. */ +extern bfd_boolean _bfd_ecoff_slurp_symbolic_info + (bfd *, asection *, struct ecoff_debug_info *); + +/* Generic ECOFF BFD backend vectors. */ + +extern bfd_boolean _bfd_ecoff_write_object_contents (bfd *); +extern const bfd_target *_bfd_ecoff_archive_p (bfd *); + +#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 + (bfd *, asection *); +extern bfd_boolean _bfd_ecoff_get_section_contents + (bfd *, asection *, void * 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 + (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_copy_private_header_data \ + _bfd_generic_bfd_copy_private_header_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 (bfd *); +#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 + (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 +#define _bfd_ecoff_bfd_is_target_special_symbol \ + ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) + +extern long _bfd_ecoff_get_symtab_upper_bound (bfd *); +extern long _bfd_ecoff_canonicalize_symtab (bfd *, asymbol **); +extern asymbol *_bfd_ecoff_make_empty_symbol (bfd *); +extern void _bfd_ecoff_print_symbol + (bfd *, void *, asymbol *, bfd_print_symbol_type); +extern void _bfd_ecoff_get_symbol_info + (bfd *, asymbol *, symbol_info *); +extern bfd_boolean _bfd_ecoff_bfd_is_local_label_name + (bfd *, const char *); +#define _bfd_ecoff_get_lineno _bfd_nosymbols_get_lineno +extern bfd_boolean _bfd_ecoff_find_nearest_line + (bfd *, asection *, asymbol **, bfd_vma, const char **, const char **, + unsigned int *); +#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_find_inliner_info _bfd_nosymbols_find_inliner_info + +#define _bfd_ecoff_get_reloc_upper_bound coff_get_reloc_upper_bound +extern long _bfd_ecoff_canonicalize_reloc + (bfd *, asection *, arelent **, asymbol **symbols); +/* ecoff_bfd_reloc_type_lookup defined by backend. */ + +extern bfd_boolean _bfd_ecoff_set_arch_mach + (bfd *, enum bfd_architecture, unsigned long); +extern bfd_boolean _bfd_ecoff_set_section_contents + (bfd *, asection *, const void * location, file_ptr, bfd_size_type); + +extern int _bfd_ecoff_sizeof_headers (bfd *, bfd_boolean); +/* 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 + (bfd *); +#define _bfd_ecoff_bfd_link_hash_table_free _bfd_generic_link_hash_table_free +extern bfd_boolean _bfd_ecoff_bfd_link_add_symbols + (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 + (bfd *, struct bfd_link_info *); + +/* Hook functions for the generic COFF section reading code. */ + +extern void * _bfd_ecoff_mkobject_hook (bfd *, void *, void *); +#define _bfd_ecoff_set_alignment_hook \ + ((void (*) (bfd *, asection *, void *)) bfd_void) +extern bfd_boolean _bfd_ecoff_set_arch_mach_hook + (bfd *, void *); +extern bfd_boolean _bfd_ecoff_styp_to_sec_flags + (bfd *, void *, const char *, asection *, flagword *); +extern bfd_boolean _bfd_ecoff_slurp_symbol_table (bfd *); + +/* 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 + (int, const struct tir_ext *, TIR *); +extern void _bfd_ecoff_swap_tir_out + (int, const TIR *, struct tir_ext *); +extern void _bfd_ecoff_swap_rndx_in + (int, const struct rndx_ext *, RNDXR *); +extern void _bfd_ecoff_swap_rndx_out + (int, const RNDXR *, struct rndx_ext *); diff --git a/contrib/binutils-2.17/bfd/linker.c b/contrib/binutils-2.17/bfd/linker.c new file mode 100644 index 0000000000..14eeae4df0 --- /dev/null +++ b/contrib/binutils-2.17/bfd/linker.c @@ -0,0 +1,3108 @@ +/* linker.c -- BFD linker routines + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + 2003, 2004, 2005, 2006 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 relocatable + 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 relocatable 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 relocatable 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 relocatable 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_add_object_symbols + (bfd *, struct bfd_link_info *, bfd_boolean collect); +static bfd_boolean generic_link_add_symbols + (bfd *, struct bfd_link_info *, bfd_boolean); +static bfd_boolean generic_link_check_archive_element_no_collect + (bfd *, struct bfd_link_info *, bfd_boolean *); +static bfd_boolean generic_link_check_archive_element_collect + (bfd *, struct bfd_link_info *, bfd_boolean *); +static bfd_boolean generic_link_check_archive_element + (bfd *, struct bfd_link_info *, bfd_boolean *, bfd_boolean); +static bfd_boolean generic_link_add_symbol_list + (bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **, + bfd_boolean); +static bfd_boolean generic_add_output_symbol + (bfd *, size_t *psymalloc, asymbol *); +static bfd_boolean default_data_link_order + (bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *); +static bfd_boolean default_indirect_link_order + (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 (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 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; + memset (&h->u.undef.next, 0, + (sizeof (struct bfd_link_hash_entry) + - offsetof (struct bfd_link_hash_entry, u.undef.next))); + } + + 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 + (struct bfd_link_hash_table *table, + bfd *abfd, + struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int entsize) +{ + 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, entsize); +} + +/* 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 (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 != 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 (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; + char prefix = '\0'; + + l = string; + if (*l == bfd_get_symbol_leading_char (abfd) || *l == info->wrap_char) + { + prefix = *l; + ++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 = bfd_malloc (amt); + if (n == NULL) + return NULL; + + n[0] = prefix; + 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 = bfd_malloc (amt); + if (n == NULL) + return NULL; + + n[0] = prefix; + 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 + (struct bfd_link_hash_table *table, + bfd_boolean (*func) (struct bfd_link_hash_entry *, void *), + void *info) +{ + bfd_hash_traverse (&table->table, + (bfd_boolean (*) (struct bfd_hash_entry *, void *)) func, + info); +} + +/* Add a symbol to the linker hash table undefs list. */ + +void +bfd_link_add_undef (struct bfd_link_hash_table *table, + struct bfd_link_hash_entry *h) +{ + BFD_ASSERT (h->u.undef.next == NULL); + if (table->undefs_tail != NULL) + table->undefs_tail->u.undef.next = h; + if (table->undefs == NULL) + table->undefs = h; + table->undefs_tail = h; +} + +/* The undefs list was designed so that in normal use we don't need to + remove entries. However, if symbols on the list are changed from + bfd_link_hash_undefined to either bfd_link_hash_undefweak or + bfd_link_hash_new for some reason, then they must be removed from the + list. Failure to do so might result in the linker attempting to add + the symbol to the list again at a later stage. */ + +void +bfd_link_repair_undef_list (struct bfd_link_hash_table *table) +{ + struct bfd_link_hash_entry **pun; + + pun = &table->undefs; + while (*pun != NULL) + { + struct bfd_link_hash_entry *h = *pun; + + if (h->type == bfd_link_hash_new + || h->type == bfd_link_hash_undefweak) + { + *pun = h->u.undef.next; + h->u.undef.next = NULL; + if (h == table->undefs_tail) + { + if (pun == &table->undefs) + table->undefs_tail = NULL; + else + /* pun points at an u.undef.next field. Go back to + the start of the link_hash_entry. */ + table->undefs_tail = (struct bfd_link_hash_entry *) + ((char *) pun - ((char *) &h->u.undef.next - (char *) h)); + break; + } + } + else + pun = &h->u.undef.next; + } +} + +/* Routine to create an entry in a generic link hash table. */ + +struct bfd_hash_entry * +_bfd_generic_link_hash_newfunc (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 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 (bfd *abfd) +{ + struct generic_link_hash_table *ret; + bfd_size_type amt = sizeof (struct generic_link_hash_table); + + ret = bfd_malloc (amt); + if (ret == NULL) + return NULL; + if (! _bfd_link_hash_table_init (&ret->root, abfd, + _bfd_generic_link_hash_newfunc, + sizeof (struct generic_link_hash_entry))) + { + free (ret); + return NULL; + } + return &ret->root; +} + +void +_bfd_generic_link_hash_table_free (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 (bfd *abfd) +{ + if (bfd_get_outsymbols (abfd) == NULL) + { + long symsize; + long symcount; + + symsize = bfd_get_symtab_upper_bound (abfd); + if (symsize < 0) + return FALSE; + bfd_get_outsymbols (abfd) = bfd_alloc (abfd, 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 (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 (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 (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 (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 (bfd *abfd, + struct bfd_link_info *info, + bfd_boolean collect) +{ + bfd_size_type symcount; + struct bfd_symbol **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; +}; + +/* Create a new entry for an archive hash table. */ + +static struct bfd_hash_entry * +archive_hash_newfunc (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 == NULL) + ret = bfd_hash_allocate (table, sizeof (struct archive_hash_entry)); + if (ret == 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 = NULL; + } + + return &ret->root; +} + +/* Initialize an archive hash table. */ + +static bfd_boolean +archive_hash_table_init + (struct archive_hash_table *table, + struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int entsize) +{ + return bfd_hash_table_init (&table->table, newfunc, entsize); +} + +/* 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 + (bfd *abfd, + struct bfd_link_info *info, + bfd_boolean (*checkfn) (bfd *, struct bfd_link_info *, bfd_boolean *)) +{ + 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, 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, + sizeof (struct archive_hash_entry))) + 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 == 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 != 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 != 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)->u.undef.next; + else + pundef = &(*pundef)->u.undef.next; + continue; + } + + /* Look for this symbol in the archive symbol map. */ + arh = archive_hash_lookup (&arsym_hash, h->root.string, FALSE, FALSE); + if (arh == 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 = 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 == NULL) + { + pundef = &(*pundef)->u.undef.next; + continue; + } + } + /* Look at all the objects which define this symbol. */ + for (l = arh->defs; l != 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 == 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)->u.undef.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 ( + 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 (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 (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 == 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 == 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 = + 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 (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 == 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 = 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 (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 (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 != NULL + && bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL)) + { + if (! (*info->callbacks->notice) (info, h->root.string, abfd, section, + value)) + return FALSE; + } + + if (hashp != 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; + h->u.undef.weak = 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, 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 = + 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->u.undef.next == NULL && info->hash->undefs_tail != h) + h->u.undef.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, 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, 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 == NULL) + return FALSE; + if (inh->type == bfd_link_hash_indirect + && inh->u.i.link == h) + { + (*_bfd_error_handler) + (_("%B: indirect symbol `%s' to `%s' is a loop"), + 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, + NULL, 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->u.undef.next == NULL && info->hash->undefs_tail != h) + h->u.undef.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), NULL, 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 u.undef.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->u.undef.next != NULL || info->hash->undefs_tail == h) + { + if (! (*info->callbacks->warning) (info, string, h->root.string, + hash_entry_bfd (h), NULL, 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) + (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 (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) = 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->map_head.link_order; 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 != 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, + &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->relocatable) + { + /* Allocate space for the output relocs for each section. */ + for (o = abfd->sections; o != NULL; o = o->next) + { + o->reloc_count = 0; + for (p = o->map_head.link_order; p != 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 = bfd_malloc (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 = 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 != NULL; o = o->next) + { + for (p = o->map_head.link_order; p != 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 (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 = bfd_realloc (bfd_get_outsymbols (output_bfd), amt); + if (newsyms == 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 (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 != NULL) + { + asection *sec; + + for (sec = input_bfd->sections; sec != 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 = 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 = 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 != 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 != 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) == 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->relocatable + || ! (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. */ + if (!bfd_is_abs_section (sym->section) + && bfd_section_removed_from_list (output_bfd, + sym->section->output_section)) + output = FALSE; + + if (output) + { + if (! generic_add_output_symbol (output_bfd, psymalloc, sym)) + return FALSE; + if (h != 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 (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 (struct generic_link_hash_entry *h, + void *data) +{ + struct generic_write_global_symbol_info *wginfo = 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 != 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 (bfd *abfd, + struct bfd_link_info *info, + asection *sec, + struct bfd_link_order *link_order) +{ + arelent *r; + + if (! info->relocatable) + abort (); + if (sec->orelocation == NULL) + abort (); + + r = bfd_alloc (abfd, sizeof (arelent)); + if (r == 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 == NULL + || ! h->written) + { + if (! ((*info->callbacks->unattached_reloc) + (info, link_order->u.reloc.p->u.name, NULL, NULL, 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_zmalloc (size); + if (buf == 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, NULL, + (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, + NULL, NULL, 0))) + { + free (buf); + return FALSE; + } + break; + } + loc = link_order->offset * bfd_octets_per_byte (abfd); + ok = bfd_set_section_contents (abfd, sec, buf, loc, 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 (bfd *abfd, asection *section) +{ + bfd_size_type amt = sizeof (struct bfd_link_order); + struct bfd_link_order *new; + + new = bfd_zalloc (abfd, amt); + if (!new) + return NULL; + + new->type = bfd_undefined_link_order; + + if (section->map_tail.link_order != NULL) + section->map_tail.link_order->next = new; + else + section->map_head.link_order = new; + section->map_tail.link_order = 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 (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 (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_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 (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); + + input_section = link_order->u.indirect.section; + input_bfd = input_section->owner; + if (input_section->size == 0) + return TRUE; + + BFD_ASSERT (input_section->output_section == output_section); + BFD_ASSERT (input_section->output_offset == link_order->offset); + BFD_ASSERT (input_section->size == link_order->size); + + if (info->relocatable + && input_section->reloc_count > 0 + && output_section->orelocation == 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 relocatable 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 = 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 = (input_section->rawsize > input_section->size + ? input_section->rawsize + : input_section->size); + contents = 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->relocatable, + _bfd_generic_link_get_symbols (input_bfd))); + if (!new_contents) + goto error_return; + + /* Output the section contents. */ + loc = input_section->output_offset * bfd_octets_per_byte (output_bfd); + if (! bfd_set_section_contents (output_bfd, output_section, + new_contents, loc, input_section->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 (struct bfd_link_order *link_order) +{ + register unsigned int c; + register struct bfd_link_order *l; + + c = 0; + for (l = link_order; l != 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 (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec ATTRIBUTE_UNUSED) +{ + return FALSE; +} + +/* +FUNCTION + bfd_section_already_linked + +SYNOPSIS + void bfd_section_already_linked (bfd *abfd, asection *sec); + +DESCRIPTION + Check if @var{sec} has been already linked during a reloceatable + or final link. + +.#define bfd_section_already_linked(abfd, sec) \ +. BFD_SEND (abfd, _section_already_linked, (abfd, sec)) +. + +*/ + +/* 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. 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. bfd_section_already_linked is called via + bfd_map_over_sections. */ + +/* The hash table. */ + +static struct bfd_hash_table _bfd_section_already_linked_table; + +/* Support routines for the hash table used by section_already_linked, + initialize the table, traverse, lookup, fill in an entry and remove + the table. */ + +void +bfd_section_already_linked_table_traverse + (bfd_boolean (*func) (struct bfd_section_already_linked_hash_entry *, + void *), void *info) +{ + bfd_hash_traverse (&_bfd_section_already_linked_table, + (bfd_boolean (*) (struct bfd_hash_entry *, + void *)) func, + info); +} + +struct bfd_section_already_linked_hash_entry * +bfd_section_already_linked_table_lookup (const char *name) +{ + return ((struct bfd_section_already_linked_hash_entry *) + bfd_hash_lookup (&_bfd_section_already_linked_table, name, + TRUE, FALSE)); +} + +void +bfd_section_already_linked_table_insert + (struct bfd_section_already_linked_hash_entry *already_linked_list, + asection *sec) +{ + struct bfd_section_already_linked *l; + + /* Allocate the memory from the same obstack as the hash table is + kept in. */ + l = bfd_hash_allocate (&_bfd_section_already_linked_table, sizeof *l); + l->sec = sec; + l->next = already_linked_list->entry; + already_linked_list->entry = l; +} + +static struct bfd_hash_entry * +already_linked_newfunc (struct bfd_hash_entry *entry ATTRIBUTE_UNUSED, + struct bfd_hash_table *table, + const char *string ATTRIBUTE_UNUSED) +{ + struct bfd_section_already_linked_hash_entry *ret = + bfd_hash_allocate (table, sizeof *ret); + + ret->entry = NULL; + + return &ret->root; +} + +bfd_boolean +bfd_section_already_linked_table_init (void) +{ + return bfd_hash_table_init_n (&_bfd_section_already_linked_table, + already_linked_newfunc, + sizeof (struct bfd_section_already_linked_hash_entry), + 42); +} + +void +bfd_section_already_linked_table_free (void) +{ + bfd_hash_table_free (&_bfd_section_already_linked_table); +} + +/* This is used on non-ELF inputs. */ + +void +_bfd_generic_section_already_linked (bfd *abfd, asection *sec) +{ + flagword flags; + const char *name; + struct bfd_section_already_linked *l; + struct bfd_section_already_linked_hash_entry *already_linked_list; + + flags = sec->flags; + 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. */ + + name = bfd_get_section_name (abfd, sec); + + already_linked_list = bfd_section_already_linked_table_lookup (name); + + for (l = already_linked_list->entry; l != NULL; l = l->next) + { + bfd_boolean skip = FALSE; + struct coff_comdat_info *s_comdat + = bfd_coff_get_comdat_section (abfd, sec); + struct coff_comdat_info *l_comdat + = bfd_coff_get_comdat_section (l->sec->owner, l->sec); + + /* We may have 3 different sections on the list: group section, + comdat section and linkonce section. SEC may be a linkonce or + comdat section. We always ignore group section. For non-COFF + inputs, we also ignore comdat section. + + FIXME: Is that safe to match a linkonce section with a comdat + section for COFF inputs? */ + if ((l->sec->flags & SEC_GROUP) != 0) + skip = TRUE; + else if (bfd_get_flavour (abfd) == bfd_target_coff_flavour) + { + if (s_comdat != NULL + && l_comdat != NULL + && strcmp (s_comdat->name, l_comdat->name) != 0) + skip = TRUE; + } + else if (l_comdat != NULL) + skip = TRUE; + + if (!skip) + { + /* 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: + (*_bfd_error_handler) + (_("%B: warning: ignoring duplicate section `%A'\n"), + abfd, sec); + 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 (sec->size != l->sec->size) + (*_bfd_error_handler) + (_("%B: warning: duplicate section `%A' has different size\n"), + abfd, sec); + break; + } + + /* Set the output_section field so that lang_add_section + does not create a lang_input_section structure for this + section. Since there might be a symbol in the section + being discarded, we must retain a pointer to the section + which we are really going to use. */ + sec->output_section = bfd_abs_section_ptr; + sec->kept_section = l->sec; + + return; + } + } + + /* This is the first section with this name. Record it. */ + bfd_section_already_linked_table_insert (already_linked_list, sec); +} + +/* Convert symbols in excluded output sections to absolute. */ + +static bfd_boolean +fix_syms (struct bfd_link_hash_entry *h, void *data) +{ + bfd *obfd = (bfd *) data; + + if (h->type == bfd_link_hash_warning) + h = h->u.i.link; + + if (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak) + { + asection *s = h->u.def.section; + if (s != NULL + && s->output_section != NULL + && (s->output_section->flags & SEC_EXCLUDE) != 0 + && bfd_section_removed_from_list (obfd, s->output_section)) + { + h->u.def.value += s->output_offset + s->output_section->vma; + h->u.def.section = bfd_abs_section_ptr; + } + } + + return TRUE; +} + +void +_bfd_fix_excluded_sec_syms (bfd *obfd, struct bfd_link_info *info) +{ + bfd_link_hash_traverse (info->hash, fix_syms, obfd); +} diff --git a/contrib/binutils-2.17/bfd/merge.c b/contrib/binutils-2.17/bfd/merge.c new file mode 100644 index 0000000000..c1795d2911 --- /dev/null +++ b/contrib/binutils-2.17/bfd/merge.c @@ -0,0 +1,873 @@ +/* SEC_MERGE support. + Copyright 2001, 2002, 2003, 2004, 2005, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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. This includes the zero terminator. */ + 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; + /* 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. */ + void **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_str; + /* Original section content. */ + unsigned char contents[1]; +}; + + +/* Routine to create an entry in a section merge hashtab. */ + +static struct bfd_hash_entry * +sec_merge_hash_newfunc (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 sec_merge_hash_entry)); + if (entry == NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + entry = bfd_hash_newfunc (entry, table, string); + + if (entry != NULL) + { + /* Initialize the local fields. */ + struct sec_merge_hash_entry *ret = (struct sec_merge_hash_entry *) entry; + + ret->u.suffix = NULL; + ret->alignment = 0; + ret->secinfo = NULL; + ret->next = NULL; + } + + return entry; +} + +/* Look up an entry in a section merge hash table. */ + +static struct sec_merge_hash_entry * +sec_merge_hash_lookup (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 != 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) + { + if (create) + { + /* Mark the less aligned copy as deleted. */ + hashp->len = 0; + hashp->alignment = 0; + } + break; + } + return hashp; + } + } + + if (! create) + return NULL; + + hashp = ((struct sec_merge_hash_entry *) + sec_merge_hash_newfunc (NULL, &table->table, string)); + if (hashp == NULL) + return 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 (unsigned int entsize, bfd_boolean strings) +{ + struct sec_merge_hash *table; + + table = bfd_malloc (sizeof (struct sec_merge_hash)); + if (table == NULL) + return NULL; + + if (! bfd_hash_table_init_n (&table->table, sec_merge_hash_newfunc, + sizeof (struct sec_merge_hash_entry), 16699)) + { + 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 (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 (bfd *abfd, struct sec_merge_hash_entry *entry) +{ + struct sec_merge_sec_info *secinfo = entry->secinfo; + asection *sec = secinfo->sec; + char *pad = NULL; + bfd_size_type off = 0; + int alignment_power = sec->output_section->alignment_power; + + if (alignment_power) + { + pad = bfd_zmalloc ((bfd_size_type) 1 << alignment_power); + if (pad == NULL) + return FALSE; + } + + for (; entry != NULL && entry->secinfo == secinfo; entry = entry->next) + { + const char *str; + bfd_size_type len; + + len = -off & (entry->alignment - 1); + if (len != 0) + { + if (bfd_bwrite (pad, len, abfd) != len) + goto err; + off += len; + } + + str = entry->root.string; + len = entry->len; + + if (bfd_bwrite (str, len, abfd) != len) + goto err; + + off += len; + } + + /* Trailing alignment needed? */ + off = sec->size - off; + if (off != 0 + && bfd_bwrite (pad, off, abfd) != off) + goto err; + + if (pad != NULL) + free (pad); + return TRUE; + + err: + if (pad != NULL) + free (pad); + return FALSE; +} + +/* Register a SEC_MERGE section as a candidate for merging. + This function is called for all non-dynamic SEC_MERGE input sections. */ + +bfd_boolean +_bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec, + void **psecinfo) +{ + struct sec_merge_info *sinfo; + struct sec_merge_sec_info *secinfo; + unsigned int align; + bfd_size_type amt; + + if ((abfd->flags & DYNAMIC) != 0 + || (sec->flags & SEC_MERGE) == 0) + abort (); + + if (sec->size == 0 + || (sec->flags & SEC_EXCLUDE) != 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 = sec->alignment_power; + if ((sec->entsize < (unsigned) 1 << align + && ((sec->entsize & (sec->entsize - 1)) + || !(sec->flags & SEC_STRINGS))) + || (sec->entsize > (unsigned) 1 << align + && (sec->entsize & (((unsigned) 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 + && secinfo->sec->alignment_power == sec->alignment_power + && secinfo->sec->output_section == sec->output_section) + break; + + if (sinfo == NULL) + { + /* Initialize the information we need to keep track of. */ + sinfo = bfd_alloc (abfd, sizeof (struct sec_merge_info)); + if (sinfo == NULL) + goto error_return; + sinfo->next = (struct sec_merge_info *) *psinfo; + sinfo->chain = NULL; + *psinfo = 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->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_str = NULL; + + sec->rawsize = sec->size; + if (! bfd_get_section_contents (sec->owner, sec, secinfo->contents, + 0, sec->size)) + goto error_return; + + return TRUE; + + error_return: + *psecinfo = NULL; + return FALSE; +} + +/* Record one section into the hash table. */ +static bfd_boolean +record_section (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 = sec->alignment_power; + end = secinfo->contents + sec->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, (char *) 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, (char *) 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, (char *) 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; +} + +static int +strrevcmp (const void *a, const void *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; + unsigned int lenA = A->len; + unsigned int lenB = B->len; + const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1; + const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1; + int l = lenA < lenB ? lenA : lenB; + + while (l) + { + if (*s != *t) + return (int) *s - (int) *t; + s--; + t--; + l--; + } + return lenA - lenB; +} + +/* Like strrevcmp, but for the case where all strings have the same + alignment > entsize. */ + +static int +strrevcmp_align (const void *a, const void *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; + unsigned int lenA = A->len; + unsigned int lenB = B->len; + const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1; + const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1; + int l = lenA < lenB ? lenA : lenB; + int tail_align = (lenA & (A->alignment - 1)) - (lenB & (A->alignment - 1)); + + if (tail_align != 0) + return tail_align; + + while (l) + { + if (*s != *t) + return (int) *s - (int) *t; + s--; + t--; + l--; + } + return lenA - lenB; +} + +static inline int +is_suffix (const struct sec_merge_hash_entry *A, + const struct sec_merge_hash_entry *B) +{ + 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) == 0; +} + +/* This is a helper function for _bfd_merge_sections. It attempts to + merge strings matching suffixes of longer strings. */ +static void +merge_strings (struct sec_merge_info *sinfo) +{ + struct sec_merge_hash_entry **array, **a, *e; + struct sec_merge_sec_info *secinfo; + bfd_size_type size, amt; + unsigned int alignment = 0; + + /* Now sort the strings */ + amt = sinfo->htab->size * sizeof (struct sec_merge_hash_entry *); + array = 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; + /* Adjust the length to not include the zero terminator. */ + e->len -= sinfo->htab->entsize; + if (alignment != e->alignment) + { + if (alignment == 0) + alignment = e->alignment; + else + alignment = (unsigned) -1; + } + } + + sinfo->htab->size = a - array; + if (sinfo->htab->size != 0) + { + qsort (array, (size_t) sinfo->htab->size, + sizeof (struct sec_merge_hash_entry *), + (alignment != (unsigned) -1 && alignment > sinfo->htab->entsize + ? strrevcmp_align : strrevcmp)); + + /* Loop over the sorted array and merge suffixes */ + e = *--a; + e->len += sinfo->htab->entsize; + while (--a >= array) + { + struct sec_merge_hash_entry *cmp = *a; + + cmp->len += sinfo->htab->entsize; + if (e->alignment >= cmp->alignment + && !((e->len - cmp->len) & (cmp->alignment - 1)) + && is_suffix (e, cmp)) + { + cmp->u.suffix = e; + cmp->alignment = 0; + } + else + e = cmp; + } + } + +alloc_failure: + if (array) + free (array); + + /* 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->size = size; + secinfo = e->secinfo; + } + if (e->alignment) + { + if (e->secinfo->first_str == NULL) + { + e->secinfo->first_str = e; + size = 0; + } + size = (size + e->alignment - 1) & ~((bfd_vma) e->alignment - 1); + e->u.index = size; + size += e->len; + } + } + secinfo->sec->size = size; + if (secinfo->sec->alignment_power != 0) + { + bfd_size_type align = (bfd_size_type) 1 << secinfo->sec->alignment_power; + secinfo->sec->size = (secinfo->sec->size + align - 1) & -align; + } + + /* 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 (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + void *xsinfo, + void (*remove_hook) (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_str == NULL) + { + if (secinfo) + secinfo->sec->size = size; + e->secinfo->first_str = 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->size = size; + } + + /* Finally remove 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_str == NULL) + secinfo->sec->flags |= SEC_EXCLUDE; + } + + return TRUE; +} + +/* Write out the merged section. */ + +bfd_boolean +_bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo) +{ + struct sec_merge_sec_info *secinfo; + file_ptr pos; + + secinfo = (struct sec_merge_sec_info *) psecinfo; + + if (secinfo->first_str == NULL) + 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_str)) + 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 (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec, + void *psecinfo, bfd_vma offset) +{ + 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 >= sec->rawsize) + { + if (offset > sec->rawsize) + { + (*_bfd_error_handler) + (_("%s: access beyond end of merged section (%ld)"), + bfd_get_filename (sec->owner), (long) offset); + } + return secinfo->first_str ? sec->size : 0; + } + + if (secinfo->htab->strings) + { + if (sec->entsize == 1) + { + p = secinfo->contents + offset - 1; + while (p >= secinfo->contents && *p) + --p; + ++p; + } + else + { + p = secinfo->contents + (offset / 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 / sec->entsize) * sec->entsize; + } + entry = sec_merge_hash_lookup (secinfo->htab, (char *) 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 / 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.17/bfd/opncls.c b/contrib/binutils-2.17/bfd/opncls.c new file mode 100644 index 0000000000..b02b137889 --- /dev/null +++ b/contrib/binutils-2.17/bfd/opncls.c @@ -0,0 +1,1452 @@ +/* opncls.c -- open and close a BFD. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, + 2001, 2002, 2003, 2004, 2005, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 (void) +{ + bfd *nbfd; + + nbfd = bfd_zmalloc (sizeof (bfd)); + if (nbfd == NULL) + return NULL; + + nbfd->id = _bfd_id_counter++; + + nbfd->memory = 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, + sizeof (struct section_hash_entry), 251)) + { + free (nbfd); + return NULL; + } + nbfd->sections = NULL; + nbfd->section_last = NULL; + nbfd->format = bfd_unknown; + nbfd->my_archive = NULL; + nbfd->origin = 0; + nbfd->opened_once = FALSE; + nbfd->output_has_begun = FALSE; + nbfd->section_count = 0; + nbfd->usrdata = 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 (bfd *obfd) +{ + bfd *nbfd; + + nbfd = _bfd_new_bfd (); + if (nbfd == NULL) + return NULL; + nbfd->xvec = obfd->xvec; + nbfd->iovec = obfd->iovec; + nbfd->my_archive = obfd; + nbfd->direction = read_direction; + nbfd->target_defaulted = obfd->target_defaulted; + return nbfd; +} + +/* Delete a BFD. */ + +void +_bfd_delete_bfd (bfd *abfd) +{ + bfd_hash_table_free (&abfd->section_htab); + objalloc_free ((struct objalloc *) abfd->memory); + free (abfd); +} + +/* +SECTION + Opening and closing BFDs + +SUBSECTION + Functions for opening and closing +*/ + +/* +FUNCTION + bfd_fopen + +SYNOPSIS + bfd *bfd_fopen (const char *filename, const char *target, + const char *mode, int fd); + +DESCRIPTION + Open the file @var{filename} with the target @var{target}. + Return a pointer to the created BFD. If @var{fd} is not -1, + then <> is used to open the file; otherwise, <> + is used. @var{mode} is passed directly to <> or + <>. + + Calls <>, so @var{target} is interpreted as by + that function. + + The new BFD is marked as cacheable iff @var{fd} is -1. + + If <> is returned then an error has occured. Possible errors + are <>, <> or + <> error. +*/ + +bfd * +bfd_fopen (const char *filename, const char *target, const char *mode, int fd) +{ + 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; + } + +#ifdef HAVE_FDOPEN + if (fd != -1) + nbfd->iostream = fdopen (fd, mode); + else +#endif + nbfd->iostream = real_fopen (filename, mode); + if (nbfd->iostream == NULL) + { + bfd_set_error (bfd_error_system_call); + _bfd_delete_bfd (nbfd); + return NULL; + } + + /* OK, put everything where it belongs. */ + nbfd->filename = filename; + + /* Figure out whether the user is opening the file for reading, + writing, or both, by looking at the MODE argument. */ + if ((mode[0] == 'r' || mode[0] == 'w' || mode[0] == 'a') + && mode[1] == '+') + nbfd->direction = both_direction; + else if (mode[0] == 'r') + nbfd->direction = read_direction; + else + nbfd->direction = write_direction; + + if (! bfd_cache_init (nbfd)) + { + _bfd_delete_bfd (nbfd); + return NULL; + } + nbfd->opened_once = TRUE; + /* If we opened the file by name, mark it cacheable; we can close it + and reopen it later. However, if a file descriptor was provided, + then it may have been opened with special flags that make it + unsafe to close and reopen the file. */ + if (fd == -1) + bfd_set_cacheable (nbfd, TRUE); + + return nbfd; +} + +/* +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 (const char *filename, const char *target) +{ + return bfd_fopen (filename, target, FOPEN_RB, -1); +} + +/* 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 caching; 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 (const char *filename, const char *target, int fd) +{ + const char *mode; +#if defined(HAVE_FCNTL) && defined(F_GETFL) + int fdflags; +#endif + +#if ! defined(HAVE_FCNTL) || ! defined(F_GETFL) + mode = FOPEN_RUB; /* Assume full access. */ +#else + fdflags = fcntl (fd, F_GETFL, NULL); + if (fdflags == -1) + { + bfd_set_error (bfd_error_system_call); + return NULL; + } + + /* (O_ACCMODE) parens are to avoid Ultrix header file bug. */ + switch (fdflags & (O_ACCMODE)) + { + case O_RDONLY: mode = FOPEN_RB; break; + case O_WRONLY: mode = FOPEN_RUB; break; + case O_RDWR: mode = FOPEN_RUB; break; + default: abort (); + } +#endif + + return bfd_fopen (filename, target, mode, fd); +} + +/* +FUNCTION + bfd_openstreamr + +SYNOPSIS + bfd *bfd_openstreamr (const char *, const char *, void *); + +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 (const char *filename, const char *target, void *streamarg) +{ + FILE *stream = 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 = stream; + nbfd->filename = filename; + nbfd->direction = read_direction; + + if (! bfd_cache_init (nbfd)) + { + _bfd_delete_bfd (nbfd); + return NULL; + } + + return nbfd; +} + +/* +FUNCTION + bfd_openr_iovec + +SYNOPSIS + bfd *bfd_openr_iovec (const char *filename, const char *target, + void *(*open) (struct bfd *nbfd, + void *open_closure), + void *open_closure, + file_ptr (*pread) (struct bfd *nbfd, + void *stream, + void *buf, + file_ptr nbytes, + file_ptr offset), + int (*close) (struct bfd *nbfd, + void *stream)); + +DESCRIPTION + + Create and return a BFD backed by a read-only @var{stream}. + The @var{stream} is created using @var{open}, accessed using + @var{pread} and destroyed using @var{close}. + + Calls <>, so @var{target} is interpreted as by + that function. + + Calls @var{open} (which can call <> and + <>) to obtain the read-only stream backing + the BFD. @var{open} either succeeds returning the + non-<> @var{stream}, or fails returning <> + (setting <>). + + Calls @var{pread} to request @var{nbytes} of data from + @var{stream} starting at @var{offset} (e.g., via a call to + <>). @var{pread} either succeeds returning the + number of bytes read (which can be less than @var{nbytes} when + end-of-file), or fails returning -1 (setting <>). + + Calls @var{close} when the BFD is later closed using + <>. @var{close} either succeeds returning 0, or + fails returning -1 (setting <>). + + If <> returns <> then an error has + occurred. Possible errors are <>, + <> and <>. + +*/ + +struct opncls +{ + void *stream; + file_ptr (*pread) (struct bfd *abfd, void *stream, void *buf, + file_ptr nbytes, file_ptr offset); + int (*close) (struct bfd *abfd, void *stream); + file_ptr where; +}; + +static file_ptr +opncls_btell (struct bfd *abfd) +{ + struct opncls *vec = abfd->iostream; + return vec->where; +} + +static int +opncls_bseek (struct bfd *abfd, file_ptr offset, int whence) +{ + struct opncls *vec = abfd->iostream; + switch (whence) + { + case SEEK_SET: vec->where = offset; break; + case SEEK_CUR: vec->where += offset; break; + case SEEK_END: return -1; + } + return 0; +} + +static file_ptr +opncls_bread (struct bfd *abfd, void *buf, file_ptr nbytes) +{ + struct opncls *vec = abfd->iostream; + file_ptr nread = (vec->pread) (abfd, vec->stream, buf, nbytes, vec->where); + if (nread < 0) + return nread; + vec->where += nread; + return nread; +} + +static file_ptr +opncls_bwrite (struct bfd *abfd ATTRIBUTE_UNUSED, + const void *where ATTRIBUTE_UNUSED, + file_ptr nbytes ATTRIBUTE_UNUSED) +{ + return -1; +} + +static int +opncls_bclose (struct bfd *abfd) +{ + struct opncls *vec = abfd->iostream; + /* Since the VEC's memory is bound to the bfd deleting the bfd will + free it. */ + int status = 0; + if (vec->close != NULL) + status = (vec->close) (abfd, vec->stream); + abfd->iostream = NULL; + return status; +} + +static int +opncls_bflush (struct bfd *abfd ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +opncls_bstat (struct bfd *abfd ATTRIBUTE_UNUSED, struct stat *sb) +{ + memset (sb, 0, sizeof (*sb)); + return 0; +} + +static const struct bfd_iovec opncls_iovec = { + &opncls_bread, &opncls_bwrite, &opncls_btell, &opncls_bseek, + &opncls_bclose, &opncls_bflush, &opncls_bstat +}; + +bfd * +bfd_openr_iovec (const char *filename, const char *target, + void *(*open) (struct bfd *nbfd, + void *open_closure), + void *open_closure, + file_ptr (*pread) (struct bfd *abfd, + void *stream, + void *buf, + file_ptr nbytes, + file_ptr offset), + int (*close) (struct bfd *nbfd, + void *stream)) +{ + bfd *nbfd; + const bfd_target *target_vec; + struct opncls *vec; + void *stream; + + 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; + + stream = open (nbfd, open_closure); + if (stream == NULL) + { + _bfd_delete_bfd (nbfd); + return NULL; + } + + vec = bfd_zalloc (nbfd, sizeof (struct opncls)); + vec->stream = stream; + vec->pread = pread; + vec->close = close; + + nbfd->iovec = &opncls_iovec; + nbfd->iostream = vec; + + 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 (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 (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; + + /* FIXME: cagney/2004-02-15: Need to implement a BFD_IN_MEMORY io + vector. */ + if (!(abfd->flags & BFD_IN_MEMORY)) + ret = abfd->iovec->bclose (abfd); + else + ret = TRUE; + + /* 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 (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 (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 (bfd *abfd) +{ + struct bfd_in_memory *bim; + + if (abfd->direction != no_direction) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + bim = bfd_malloc (sizeof (struct bfd_in_memory)); + abfd->iostream = 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 (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 = NULL; + abfd->origin = 0; + abfd->opened_once = FALSE; + abfd->output_has_begun = FALSE; + abfd->section_count = 0; + abfd->usrdata = 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 + void *bfd_alloc (bfd *abfd, bfd_size_type wanted); + +DESCRIPTION + Allocate a block of @var{wanted} bytes of memory attached to + <> and return a pointer to it. +*/ + +void * +bfd_alloc (bfd *abfd, bfd_size_type size) +{ + void *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; +} + +/* +INTERNAL_FUNCTION + bfd_alloc2 + +SYNOPSIS + void *bfd_alloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size); + +DESCRIPTION + Allocate a block of @var{nmemb} elements of @var{size} bytes each + of memory attached to <> and return a pointer to it. +*/ + +void * +bfd_alloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size) +{ + void *ret; + + if ((nmemb | size) >= HALF_BFD_SIZE_TYPE + && size != 0 + && nmemb > ~(bfd_size_type) 0 / size) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + size *= nmemb; + + 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; +} + +/* +INTERNAL_FUNCTION + bfd_zalloc + +SYNOPSIS + void *bfd_zalloc (bfd *abfd, bfd_size_type wanted); + +DESCRIPTION + Allocate a block of @var{wanted} bytes of zeroed memory + attached to <> and return a pointer to it. +*/ + +void * +bfd_zalloc (bfd *abfd, bfd_size_type size) +{ + void *res; + + res = bfd_alloc (abfd, size); + if (res) + memset (res, 0, (size_t) size); + return res; +} + +/* +INTERNAL_FUNCTION + bfd_zalloc2 + +SYNOPSIS + void *bfd_zalloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size); + +DESCRIPTION + Allocate a block of @var{nmemb} elements of @var{size} bytes each + of zeroed memory attached to <> and return a pointer to it. +*/ + +void * +bfd_zalloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size) +{ + void *res; + + if ((nmemb | size) >= HALF_BFD_SIZE_TYPE + && size != 0 + && nmemb > ~(bfd_size_type) 0 / size) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + size *= nmemb; + + 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 (bfd *abfd, void *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). +*/ + +#define GNU_DEBUGLINK ".gnu_debuglink" +/* +FUNCTION + bfd_calc_gnu_debuglink_crc32 + +SYNOPSIS + unsigned long bfd_calc_gnu_debuglink_crc32 + (unsigned long crc, const unsigned char *buf, bfd_size_type len); + +DESCRIPTION + Computes a CRC value as used in the .gnu_debuglink section. + Advances the previously computed @var{crc} value by computing + and adding in the crc32 for @var{len} bytes of @var{buf}. + +RETURNS + Return the updated CRC32 value. +*/ + +unsigned long +bfd_calc_gnu_debuglink_crc32 (unsigned long crc, + const unsigned char *buf, + bfd_size_type 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 (bfd *abfd, unsigned long *crc32_out) +{ + asection *sect; + unsigned long crc32; + bfd_byte *contents; + int crc_offset; + char *name; + + BFD_ASSERT (abfd); + BFD_ASSERT (crc32_out); + + sect = bfd_get_section_by_name (abfd, GNU_DEBUGLINK); + + if (sect == NULL) + return NULL; + + if (!bfd_malloc_and_get_section (abfd, sect, &contents)) + { + if (contents != NULL) + free (contents); + return NULL; + } + + /* Crc value is stored after the filename, aligned up to 4 bytes. */ + name = (char *) contents; + crc_offset = strlen (name) + 1; + crc_offset = (crc_offset + 3) & ~3; + + crc32 = bfd_get_32 (abfd, contents + crc_offset); + + *crc32_out = crc32; + return name; +} + +/* +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 (const char *name, const unsigned long crc) +{ + static unsigned char buffer [8 * 1024]; + unsigned long file_crc = 0; + int fd; + bfd_size_type count; + + BFD_ASSERT (name); + + fd = open (name, O_RDONLY); + if (fd < 0) + return FALSE; + + while ((count = read (fd, buffer, sizeof (buffer))) > 0) + file_crc = bfd_calc_gnu_debuglink_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 (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 = strdup (abfd->filename); + if (dir == NULL) + { + free (basename); + return NULL; + } + 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 = malloc (strlen (debug_file_directory) + 1 + + strlen (dir) + + strlen (".debug/") + + strlen (basename) + + 1); + if (debugfile == NULL) + { + free (basename); + free (dir); + return NULL; + } + + /* 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, it examines the section for the name and checksum + of a '.debug' file containing auxiliary debugging information. It + then searches the filesystem for this .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, it will search a default path configured into + libbfd at build time. [XXX this feature is not currently + implemented]. + +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 (bfd *abfd, const char *dir) +{ + return find_separate_debug_file (abfd, dir); +} + +/* +FUNCTION + bfd_create_gnu_debuglink_section + +SYNOPSIS + struct bfd_section *bfd_create_gnu_debuglink_section + (bfd *abfd, const char *filename); + +DESCRIPTION + + Takes a @var{BFD} and adds a .gnu_debuglink section to it. The section is sized + to be big enough to contain a link to the specified @var{filename}. + +RETURNS + A pointer to the new section is returned if all is ok. Otherwise <> is + returned and bfd_error is set. +*/ + +asection * +bfd_create_gnu_debuglink_section (bfd *abfd, const char *filename) +{ + asection *sect; + bfd_size_type debuglink_size; + + if (abfd == NULL || filename == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return NULL; + } + + /* Strip off any path components in filename. */ + filename = lbasename (filename); + + sect = bfd_get_section_by_name (abfd, GNU_DEBUGLINK); + if (sect) + { + /* Section already exists. */ + bfd_set_error (bfd_error_invalid_operation); + return NULL; + } + + sect = bfd_make_section (abfd, GNU_DEBUGLINK); + if (sect == NULL) + return NULL; + + if (! bfd_set_section_flags (abfd, sect, + SEC_HAS_CONTENTS | SEC_READONLY | SEC_DEBUGGING)) + /* XXX Should we delete the section from the bfd ? */ + return NULL; + + + debuglink_size = strlen (filename) + 1; + debuglink_size += 3; + debuglink_size &= ~3; + debuglink_size += 4; + + if (! bfd_set_section_size (abfd, sect, debuglink_size)) + /* XXX Should we delete the section from the bfd ? */ + return NULL; + + return sect; +} + + +/* +FUNCTION + bfd_fill_in_gnu_debuglink_section + +SYNOPSIS + bfd_boolean bfd_fill_in_gnu_debuglink_section + (bfd *abfd, struct bfd_section *sect, const char *filename); + +DESCRIPTION + + Takes a @var{BFD} and containing a .gnu_debuglink section @var{SECT} + and fills in the contents of the section to contain a link to the + specified @var{filename}. The filename should be relative to the + current directory. + +RETURNS + <> is returned if all is ok. Otherwise <> is returned + and bfd_error is set. +*/ + +bfd_boolean +bfd_fill_in_gnu_debuglink_section (bfd *abfd, + struct bfd_section *sect, + const char *filename) +{ + bfd_size_type debuglink_size; + unsigned long crc32; + char * contents; + bfd_size_type crc_offset; + FILE * handle; + static unsigned char buffer[8 * 1024]; + size_t count; + + if (abfd == NULL || sect == NULL || filename == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + /* Make sure that we can read the file. + XXX - Should we attempt to locate the debug info file using the same + algorithm as gdb ? At the moment, since we are creating the + .gnu_debuglink section, we insist upon the user providing us with a + correct-for-section-creation-time path, but this need not conform to + the gdb location algorithm. */ + handle = real_fopen (filename, FOPEN_RB); + if (handle == NULL) + { + bfd_set_error (bfd_error_system_call); + return FALSE; + } + + crc32 = 0; + while ((count = fread (buffer, 1, sizeof buffer, handle)) > 0) + crc32 = bfd_calc_gnu_debuglink_crc32 (crc32, buffer, count); + fclose (handle); + + /* Strip off any path components in filename, + now that we no longer need them. */ + filename = lbasename (filename); + + debuglink_size = strlen (filename) + 1; + debuglink_size += 3; + debuglink_size &= ~3; + debuglink_size += 4; + + contents = malloc (debuglink_size); + if (contents == NULL) + { + /* XXX Should we delete the section from the bfd ? */ + bfd_set_error (bfd_error_no_memory); + return FALSE; + } + + strcpy (contents, filename); + crc_offset = debuglink_size - 4; + + bfd_put_32 (abfd, crc32, contents + crc_offset); + + if (! bfd_set_section_contents (abfd, sect, contents, 0, debuglink_size)) + { + /* XXX Should we delete the section from the bfd ? */ + free (contents); + return FALSE; + } + + return TRUE; +} diff --git a/contrib/binutils-2.17/bfd/reloc.c b/contrib/binutils-2.17/bfd/reloc.c new file mode 100644 index 0000000000..f1d09a5ab0 --- /dev/null +++ b/contrib/binutils-2.17/bfd/reloc.c @@ -0,0 +1,4939 @@ +/* BFD support for handling relocation entries. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004, 2005, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 bfd_symbol **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 value overflows when considered as a signed +. number one bit larger than the field. ie. A bitfield of N bits +. is allowed to represent -2**n to 2**n-1. *} +. complain_overflow_bitfield, +. +. {* Complain if the value overflows when considered as a 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 bfd_symbol; {* 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 accommodated (e.g., i960 callj +. instructions). *} +. bfd_reloc_status_type (*special_function) +. (bfd *, arelent *, struct bfd_symbol *, void *, 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 != 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 (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 (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; + + /* 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); + signmask = ~fieldmask; + addrmask = N_ONES (addrsize) | fieldmask; + a = (relocation & addrmask) >> rightshift;; + + 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. */ + signmask = ~ (fieldmask >> 1); + /* Fall thru */ + + 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. */ + 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. */ + if ((a & signmask) != 0) + 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, + void *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 (bfd *abfd, + arelent *reloc_entry, + void *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 != NULL) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* If we are not producing relocatable 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 == 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 > bfd_get_section_limit (abfd, input_section)) + return bfd_reloc_outofrange; + + /* Work out which section the relocation is targeted 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 relocatable 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 relocatable 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 != 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) + { + /* 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 +relocatable 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 relocatable output. When +we are producing relocatable output, logically we should do exactly +what we do when not producing relocatable 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 relocatable 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; + 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, + void *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 (bfd *abfd, + arelent *reloc_entry, + void *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 > bfd_get_section_limit (abfd, input_section)) + return bfd_reloc_outofrange; + + /* Work out which section the relocation is targeted 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 relocatable 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 relocatable 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) + { + + /* 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 +relocatable 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 relocatable output. When +we are producing relocatable output, logically we should do exactly +what we do when not producing relocatable 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 relocatable 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; + /* FIXME: There should be no target specific code here... */ + if (strcmp (abfd->xvec->name, "coff-z8k") != 0) + 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, data); + DOIT (x); + bfd_put_8 (abfd, x, data); + } + break; + + case 1: + { + short x = bfd_get_16 (abfd, data); + DOIT (x); + bfd_put_16 (abfd, (bfd_vma) x, data); + } + break; + case 2: + { + long x = bfd_get_32 (abfd, data); + DOIT (x); + bfd_put_32 (abfd, (bfd_vma) x, data); + } + break; + case -2: + { + long x = bfd_get_32 (abfd, data); + relocation = -relocation; + DOIT (x); + bfd_put_32 (abfd, (bfd_vma) x, data); + } + break; + + case 3: + /* Do nothing */ + break; + + case 4: + { + bfd_vma x = bfd_get_64 (abfd, data); + DOIT (x); + bfd_put_64 (abfd, x, 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 + relocatable 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 (reloc_howto_type *howto, + bfd *input_bfd, + asection *input_section, + bfd_byte *contents, + bfd_vma address, + bfd_vma value, + bfd_vma addend) +{ + bfd_vma relocation; + + /* Sanity check the address. */ + if (address > bfd_get_section_limit (input_bfd, input_section)) + return bfd_reloc_outofrange; + + /* This function assumes that we are dealing with a basic relocation + against a symbol. We want to compute the value of the symbol to + relocate to. This is just VALUE, the value of the symbol, plus + ADDEND, any addend associated with the reloc. */ + relocation = value + addend; + + /* If the relocation is PC relative, we want to set RELOCATION to + the distance between the symbol (currently in RELOCATION) and the + location we are relocating. Some targets (e.g., i386-aout) + arrange for the contents of the section to be the negative of the + offset of the location within the section; for such targets + pcrel_offset is FALSE. Other targets (e.g., m88kbcs or ELF) + simply leave the contents of the section as zero; for such + targets pcrel_offset is TRUE. If pcrel_offset is FALSE we do not + need to subtract out the offset of the location within the + section (which is just ADDRESS). */ + if (howto->pc_relative) + { + relocation -= (input_section->output_section->vma + + input_section->output_offset); + if (howto->pcrel_offset) + relocation -= address; + } + + return _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 (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); + signmask = ~fieldmask; + addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask; + a = (relocation & addrmask) >> rightshift; + b = (x & howto->src_mask & addrmask) >> bitpos; + + switch (howto->complain_on_overflow) + { + case complain_overflow_signed: + /* If any sign bits are set, all sign bits must be set. + That is, A must be a valid negative address after + shifting. */ + signmask = ~(fieldmask >> 1); + /* Fall thru */ + + case complain_overflow_bitfield: + /* Much like the signed check, but for a field one bit + wider. We allow a bitfield to represent numbers in the + range -2**n to 2**n-1, where n is the number of bits in the + field. Note that when bfd_vma is 32 bits, a 32-bit reloc + can't overflow, which is exactly what we want. */ + ss = a & signmask; + if (ss != 0 && ss != ((addrmask >> rightshift) & signmask)) + flag = bfd_reloc_overflow; + + /* We only need this next bit of code if the sign bit of B + is below the sign bit of A. This would only happen if + SRC_MASK had fewer bits than BITSIZE. Note that if + SRC_MASK has more bits than BITSIZE, we can get into + trouble; we would need to verify that B is in range, as + we do for A above. */ + ss = ((~howto->src_mask) >> 1) & howto->src_mask; + ss >>= bitpos; + + /* Set all the bits above the sign bit. */ + b = (b ^ ss) - ss; + + /* Now we can do the addition. */ + sum = a + b; + + /* See if the result has the correct sign. Bits above the + sign bit are junk now; ignore them. If the sum is + positive, make sure we did not have all negative inputs; + if the sum is negative, make sure we did not have all + positive inputs. The test below looks only at the sign + bits, and it really just + SIGN (A) == SIGN (B) && SIGN (A) != SIGN (SUM) + + We mask with addrmask here to explicitly allow an address + wrap-around. The Linux kernel relies on it, and it is + the only way to write assembler code which can run when + loaded at a location 0x80000000 away from the location at + which it is linked. */ + if (((~(a ^ b)) & (a ^ sum)) & signmask & addrmask) + flag = bfd_reloc_overflow; + break; + + case complain_overflow_unsigned: + /* Checking for an unsigned overflow is relatively easy: + trim the addresses and add, and trim the result as well. + Overflow is normally indicated when the result does not + fit in the field. However, we also need to consider the + case when, e.g., fieldmask is 0x7fffffff or smaller, an + input is 0x80000000, and bfd_vma is only 32 bits; then we + will get sum == 0, but there is an overflow, since the + inputs did not fit in the field. Instead of doing a + separate test, we can check for this by or-ing in the + operands when testing for the sum overflowing its final + field. */ + sum = (a + b) & addrmask; + if ((a | b | sum) & signmask) + flag = bfd_reloc_overflow; + break; + + default: + abort (); + } + } + + /* Put RELOCATION in the right bits. */ + relocation >>= (bfd_vma) rightshift; + relocation <<= (bfd_vma) bitpos; + + /* Add RELOCATION to the right bits of X. */ + 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 + +SUBSECTION + 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_SECREL +ENUMDOC + Section relative relocations. Some targets need this for DWARF2. + +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_HI16_PCREL +ENUMDOC + High 16 bits of 32-bit pc-relative value +ENUM + BFD_RELOC_HI16_S_PCREL +ENUMDOC + High 16 bits of 32-bit pc-relative value, adjusted +ENUM + BFD_RELOC_LO16_PCREL +ENUMDOC + Low 16 bits of pc-relative value + +ENUM + BFD_RELOC_MIPS16_HI16 +ENUMDOC + MIPS16 high 16 bits of 32-bit value. +ENUM + BFD_RELOC_MIPS16_HI16_S +ENUMDOC + MIPS16 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_MIPS16_LO16 +ENUMDOC + MIPS16 low 16 bits. + +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 +ENUMX + BFD_RELOC_MIPS_TLS_DTPMOD32 +ENUMX + BFD_RELOC_MIPS_TLS_DTPREL32 +ENUMX + BFD_RELOC_MIPS_TLS_DTPMOD64 +ENUMX + BFD_RELOC_MIPS_TLS_DTPREL64 +ENUMX + BFD_RELOC_MIPS_TLS_GD +ENUMX + BFD_RELOC_MIPS_TLS_LDM +ENUMX + BFD_RELOC_MIPS_TLS_DTPREL_HI16 +ENUMX + BFD_RELOC_MIPS_TLS_DTPREL_LO16 +ENUMX + BFD_RELOC_MIPS_TLS_GOTTPREL +ENUMX + BFD_RELOC_MIPS_TLS_TPREL32 +ENUMX + BFD_RELOC_MIPS_TLS_TPREL64 +ENUMX + BFD_RELOC_MIPS_TLS_TPREL_HI16 +ENUMX + BFD_RELOC_MIPS_TLS_TPREL_LO16 +ENUMDOC + MIPS ELF relocations. +COMMENT + +ENUM + BFD_RELOC_MIPS_COPY +ENUMX + BFD_RELOC_MIPS_JUMP_SLOT +ENUMDOC + MIPS ELF relocations (VxWorks extensions). +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 +ENUMX + BFD_RELOC_FRV_GOT12 +ENUMX + BFD_RELOC_FRV_GOTHI +ENUMX + BFD_RELOC_FRV_GOTLO +ENUMX + BFD_RELOC_FRV_FUNCDESC +ENUMX + BFD_RELOC_FRV_FUNCDESC_GOT12 +ENUMX + BFD_RELOC_FRV_FUNCDESC_GOTHI +ENUMX + BFD_RELOC_FRV_FUNCDESC_GOTLO +ENUMX + BFD_RELOC_FRV_FUNCDESC_VALUE +ENUMX + BFD_RELOC_FRV_FUNCDESC_GOTOFF12 +ENUMX + BFD_RELOC_FRV_FUNCDESC_GOTOFFHI +ENUMX + BFD_RELOC_FRV_FUNCDESC_GOTOFFLO +ENUMX + BFD_RELOC_FRV_GOTOFF12 +ENUMX + BFD_RELOC_FRV_GOTOFFHI +ENUMX + BFD_RELOC_FRV_GOTOFFLO +ENUMX + BFD_RELOC_FRV_GETTLSOFF +ENUMX + BFD_RELOC_FRV_TLSDESC_VALUE +ENUMX + BFD_RELOC_FRV_GOTTLSDESC12 +ENUMX + BFD_RELOC_FRV_GOTTLSDESCHI +ENUMX + BFD_RELOC_FRV_GOTTLSDESCLO +ENUMX + BFD_RELOC_FRV_TLSMOFF12 +ENUMX + BFD_RELOC_FRV_TLSMOFFHI +ENUMX + BFD_RELOC_FRV_TLSMOFFLO +ENUMX + BFD_RELOC_FRV_GOTTLSOFF12 +ENUMX + BFD_RELOC_FRV_GOTTLSOFFHI +ENUMX + BFD_RELOC_FRV_GOTTLSOFFLO +ENUMX + BFD_RELOC_FRV_TLSOFF +ENUMX + BFD_RELOC_FRV_TLSDESC_RELAX +ENUMX + BFD_RELOC_FRV_GETTLSOFF_RELAX +ENUMX + BFD_RELOC_FRV_TLSOFF_RELAX +ENUMX + BFD_RELOC_FRV_TLSMOFF +ENUMDOC + Fujitsu Frv Relocations. +COMMENT + +ENUM + BFD_RELOC_MN10300_GOTOFF24 +ENUMDOC + This is a 24bit GOT-relative reloc for the mn10300. +ENUM + BFD_RELOC_MN10300_GOT32 +ENUMDOC + This is a 32bit GOT-relative reloc for the mn10300, offset by two bytes + in the instruction. +ENUM + BFD_RELOC_MN10300_GOT24 +ENUMDOC + This is a 24bit GOT-relative reloc for the mn10300, offset by two bytes + in the instruction. +ENUM + BFD_RELOC_MN10300_GOT16 +ENUMDOC + This is a 16bit GOT-relative reloc for the mn10300, offset by two bytes + in the instruction. +ENUM + BFD_RELOC_MN10300_COPY +ENUMDOC + Copy symbol at runtime. +ENUM + BFD_RELOC_MN10300_GLOB_DAT +ENUMDOC + Create GOT entry. +ENUM + BFD_RELOC_MN10300_JMP_SLOT +ENUMDOC + Create PLT entry. +ENUM + BFD_RELOC_MN10300_RELATIVE +ENUMDOC + Adjust by program base. +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 +ENUMX + BFD_RELOC_386_TLS_GOTDESC +ENUMX + BFD_RELOC_386_TLS_DESC_CALL +ENUMX + BFD_RELOC_386_TLS_DESC +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 +ENUMX + BFD_RELOC_X86_64_GOTOFF64 +ENUMX + BFD_RELOC_X86_64_GOTPC32 +ENUMX + BFD_RELOC_X86_64_GOT64 +ENUMX + BFD_RELOC_X86_64_GOTPCREL64 +ENUMX + BFD_RELOC_X86_64_GOTPC64 +ENUMX + BFD_RELOC_X86_64_GOTPLT64 +ENUMX + BFD_RELOC_X86_64_PLTOFF64 +ENUMX + BFD_RELOC_X86_64_GOTPC32_TLSDESC +ENUMX + BFD_RELOC_X86_64_TLSDESC_CALL +ENUMX + BFD_RELOC_X86_64_TLSDESC +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 constructor 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_PCREL_CALL +ENUMDOC + ARM 26-bit pc-relative branch for an unconditional BL or BLX instruction. +ENUM + BFD_RELOC_ARM_PCREL_JUMP +ENUMDOC + ARM 26-bit pc-relative branch for B or conditional BL instruction. + +ENUM + BFD_RELOC_THUMB_PCREL_BRANCH7 +ENUMX + BFD_RELOC_THUMB_PCREL_BRANCH9 +ENUMX + BFD_RELOC_THUMB_PCREL_BRANCH12 +ENUMX + BFD_RELOC_THUMB_PCREL_BRANCH20 +ENUMX + BFD_RELOC_THUMB_PCREL_BRANCH23 +ENUMX + BFD_RELOC_THUMB_PCREL_BRANCH25 +ENUMDOC + Thumb 7-, 9-, 12-, 20-, 23-, and 25-bit pc-relative branches. + The lowest bit must be zero and is not stored in the instruction. + Note that the corresponding ELF R_ARM_THM_JUMPnn constant has an + "nn" one smaller in all cases. Note further that BRANCH23 + corresponds to R_ARM_THM_CALL. + +ENUM + BFD_RELOC_ARM_OFFSET_IMM +ENUMDOC + 12-bit immediate offset, used in ARM-format ldr and str instructions. + +ENUM + BFD_RELOC_ARM_THUMB_OFFSET +ENUMDOC + 5-bit immediate offset, used in Thumb-format ldr and str instructions. + +ENUM + BFD_RELOC_ARM_TARGET1 +ENUMDOC + Pc-relative or absolute relocation depending on target. Used for + entries in .init_array sections. +ENUM + BFD_RELOC_ARM_ROSEGREL32 +ENUMDOC + Read-only segment base relative address. +ENUM + BFD_RELOC_ARM_SBREL32 +ENUMDOC + Data segment base relative address. +ENUM + BFD_RELOC_ARM_TARGET2 +ENUMDOC + This reloc is used for references to RTTI data from exception handling + tables. The actual definition depends on the target. It may be a + pc-relative or some form of GOT-indirect relocation. +ENUM + BFD_RELOC_ARM_PREL31 +ENUMDOC + 31-bit PC relative address. + +ENUM + BFD_RELOC_ARM_JUMP_SLOT +ENUMX + BFD_RELOC_ARM_GLOB_DAT +ENUMX + BFD_RELOC_ARM_GOT32 +ENUMX + BFD_RELOC_ARM_PLT32 +ENUMX + BFD_RELOC_ARM_RELATIVE +ENUMX + BFD_RELOC_ARM_GOTOFF +ENUMX + BFD_RELOC_ARM_GOTPC +ENUMDOC + Relocations for setting up GOTs and PLTs for shared libraries. + +ENUM + BFD_RELOC_ARM_TLS_GD32 +ENUMX + BFD_RELOC_ARM_TLS_LDO32 +ENUMX + BFD_RELOC_ARM_TLS_LDM32 +ENUMX + BFD_RELOC_ARM_TLS_DTPOFF32 +ENUMX + BFD_RELOC_ARM_TLS_DTPMOD32 +ENUMX + BFD_RELOC_ARM_TLS_TPOFF32 +ENUMX + BFD_RELOC_ARM_TLS_IE32 +ENUMX + BFD_RELOC_ARM_TLS_LE32 +ENUMDOC + ARM thread-local storage relocations. + +ENUM + BFD_RELOC_ARM_IMMEDIATE +ENUMX + BFD_RELOC_ARM_ADRL_IMMEDIATE +ENUMX + BFD_RELOC_ARM_T32_IMMEDIATE +ENUMX + BFD_RELOC_ARM_T32_IMM12 +ENUMX + BFD_RELOC_ARM_T32_ADD_PC12 +ENUMX + BFD_RELOC_ARM_SHIFT_IMM +ENUMX + BFD_RELOC_ARM_SMC +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_T32_CP_OFF_IMM +ENUMX + BFD_RELOC_ARM_T32_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_T32_OFFSET_U8 +ENUMX + BFD_RELOC_ARM_T32_OFFSET_IMM +ENUMX + BFD_RELOC_ARM_HWLITERAL +ENUMX + BFD_RELOC_ARM_THUMB_ADD +ENUMX + BFD_RELOC_ARM_THUMB_IMM +ENUMX + BFD_RELOC_ARM_THUMB_SHIFT +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_IMM3 +ENUMX + BFD_RELOC_SH_IMM3U +ENUMX + BFD_RELOC_SH_DISP12 +ENUMX + BFD_RELOC_SH_DISP12BY2 +ENUMX + BFD_RELOC_SH_DISP12BY4 +ENUMX + BFD_RELOC_SH_DISP12BY8 +ENUMX + BFD_RELOC_SH_DISP20 +ENUMX + BFD_RELOC_SH_DISP20BY8 +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_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_BFIN_16_IMM +ENUMDOC + ADI Blackfin 16 bit immediate absolute reloc. +ENUM + BFD_RELOC_BFIN_16_HIGH +ENUMDOC + ADI Blackfin 16 bit immediate absolute reloc higher 16 bits. +ENUM + BFD_RELOC_BFIN_4_PCREL +ENUMDOC + ADI Blackfin 'a' part of LSETUP. +ENUM + BFD_RELOC_BFIN_5_PCREL +ENUMDOC + ADI Blackfin. +ENUM + BFD_RELOC_BFIN_16_LOW +ENUMDOC + ADI Blackfin 16 bit immediate absolute reloc lower 16 bits. +ENUM + BFD_RELOC_BFIN_10_PCREL +ENUMDOC + ADI Blackfin. +ENUM + BFD_RELOC_BFIN_11_PCREL +ENUMDOC + ADI Blackfin 'b' part of LSETUP. +ENUM + BFD_RELOC_BFIN_12_PCREL_JUMP +ENUMDOC + ADI Blackfin. +ENUM + BFD_RELOC_BFIN_12_PCREL_JUMP_S +ENUMDOC + ADI Blackfin Short jump, pcrel. +ENUM + BFD_RELOC_BFIN_24_PCREL_CALL_X +ENUMDOC + ADI Blackfin Call.x not implemented. +ENUM + BFD_RELOC_BFIN_24_PCREL_JUMP_L +ENUMDOC + ADI Blackfin Long Jump pcrel. +ENUM + BFD_RELOC_BFIN_GOT17M4 +ENUMX + BFD_RELOC_BFIN_GOTHI +ENUMX + BFD_RELOC_BFIN_GOTLO +ENUMX + BFD_RELOC_BFIN_FUNCDESC +ENUMX + BFD_RELOC_BFIN_FUNCDESC_GOT17M4 +ENUMX + BFD_RELOC_BFIN_FUNCDESC_GOTHI +ENUMX + BFD_RELOC_BFIN_FUNCDESC_GOTLO +ENUMX + BFD_RELOC_BFIN_FUNCDESC_VALUE +ENUMX + BFD_RELOC_BFIN_FUNCDESC_GOTOFF17M4 +ENUMX + BFD_RELOC_BFIN_FUNCDESC_GOTOFFHI +ENUMX + BFD_RELOC_BFIN_FUNCDESC_GOTOFFLO +ENUMX + BFD_RELOC_BFIN_GOTOFF17M4 +ENUMX + BFD_RELOC_BFIN_GOTOFFHI +ENUMX + BFD_RELOC_BFIN_GOTOFFLO +ENUMDOC + ADI Blackfin FD-PIC relocations. +ENUM + BFD_RELOC_BFIN_GOT +ENUMDOC + ADI Blackfin GOT relocation. +ENUM + BFD_RELOC_BFIN_PLTPC +ENUMDOC + ADI Blackfin PLTPC relocation. +ENUM + BFD_ARELOC_BFIN_PUSH +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_CONST +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_ADD +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_SUB +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_MULT +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_DIV +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_MOD +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_LSHIFT +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_RSHIFT +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_AND +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_OR +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_XOR +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_LAND +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_LOR +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_LEN +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_NEG +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_COMP +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_PAGE +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_HWPAGE +ENUMDOC + ADI Blackfin arithmetic relocation. +ENUM + BFD_ARELOC_BFIN_ADDR +ENUMDOC + ADI Blackfin arithmetic relocation. + +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_M32C_HI8 +ENUMX + BFD_RELOC_M32C_RL_JUMP +ENUMX + BFD_RELOC_M32C_RL_1ADDR +ENUMX + BFD_RELOC_M32C_RL_2ADDR +ENUMDOC + Renesas M16C/M32C Relocations. + +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_M32R_GOT24 +ENUMX + BFD_RELOC_M32R_26_PLTREL +ENUMX + BFD_RELOC_M32R_COPY +ENUMX + BFD_RELOC_M32R_GLOB_DAT +ENUMX + BFD_RELOC_M32R_JMP_SLOT +ENUMX + BFD_RELOC_M32R_RELATIVE +ENUMX + BFD_RELOC_M32R_GOTOFF +ENUMX + BFD_RELOC_M32R_GOTOFF_HI_ULO +ENUMX + BFD_RELOC_M32R_GOTOFF_HI_SLO +ENUMX + BFD_RELOC_M32R_GOTOFF_LO +ENUMX + BFD_RELOC_M32R_GOTPC24 +ENUMX + BFD_RELOC_M32R_GOT16_HI_ULO +ENUMX + BFD_RELOC_M32R_GOT16_HI_SLO +ENUMX + BFD_RELOC_M32R_GOT16_LO +ENUMX + BFD_RELOC_M32R_GOTPC_HI_ULO +ENUMX + BFD_RELOC_M32R_GOTPC_HI_SLO +ENUMX + BFD_RELOC_M32R_GOTPC_LO +ENUMDOC + For PIC. + + +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-contiguously 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-contiguously 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_V850_LO16_SPLIT_OFFSET +ENUMDOC + This is a variation of BFD_RELOC_LO16 that can be used in v850e ld.bu + instructions. +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 +ENUMX + BFD_RELOC_MMIX_PUSHJ_STUBBABLE +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_MS8_LDI +ENUMDOC + This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit + of 32 bit value) 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_MS8_LDI_NEG +ENUMDOC + This is a 16 bit reloc for the AVR that stores negated 8 bit value (msb + of 32 bit value) into 8 bit immediate value of LDI 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_AVR_LDI +ENUMDOC + This is a 16 bit reloc for the AVR that stores all needed bits + for absolute addressing with ldi with overflow check to linktime +ENUM + BFD_RELOC_AVR_6 +ENUMDOC + This is a 6 bit reloc for the AVR that stores offset for ldd/std + instructions +ENUM + BFD_RELOC_AVR_6_ADIW +ENUMDOC + This is a 6 bit reloc for the AVR that stores offset for adiw/sbiw + instructions + +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_390_20 +ENUMX + BFD_RELOC_390_GOT20 +ENUMX + BFD_RELOC_390_GOTPLT20 +ENUMX + BFD_RELOC_390_TLS_GOTIE20 +ENUMDOC + Long displacement extension. + +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 inheritance 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 branches 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_M68HC12_5B +ENUMDOC + Motorola 68HC12 reloc. + This is the 5 bits of a value. + +ENUM + BFD_RELOC_16C_NUM08 +ENUMX + BFD_RELOC_16C_NUM08_C +ENUMX + BFD_RELOC_16C_NUM16 +ENUMX + BFD_RELOC_16C_NUM16_C +ENUMX + BFD_RELOC_16C_NUM32 +ENUMX + BFD_RELOC_16C_NUM32_C +ENUMX + BFD_RELOC_16C_DISP04 +ENUMX + BFD_RELOC_16C_DISP04_C +ENUMX + BFD_RELOC_16C_DISP08 +ENUMX + BFD_RELOC_16C_DISP08_C +ENUMX + BFD_RELOC_16C_DISP16 +ENUMX + BFD_RELOC_16C_DISP16_C +ENUMX + BFD_RELOC_16C_DISP24 +ENUMX + BFD_RELOC_16C_DISP24_C +ENUMX + BFD_RELOC_16C_DISP24a +ENUMX + BFD_RELOC_16C_DISP24a_C +ENUMX + BFD_RELOC_16C_REG04 +ENUMX + BFD_RELOC_16C_REG04_C +ENUMX + BFD_RELOC_16C_REG04a +ENUMX + BFD_RELOC_16C_REG04a_C +ENUMX + BFD_RELOC_16C_REG14 +ENUMX + BFD_RELOC_16C_REG14_C +ENUMX + BFD_RELOC_16C_REG16 +ENUMX + BFD_RELOC_16C_REG16_C +ENUMX + BFD_RELOC_16C_REG20 +ENUMX + BFD_RELOC_16C_REG20_C +ENUMX + BFD_RELOC_16C_ABS20 +ENUMX + BFD_RELOC_16C_ABS20_C +ENUMX + BFD_RELOC_16C_ABS24 +ENUMX + BFD_RELOC_16C_ABS24_C +ENUMX + BFD_RELOC_16C_IMM04 +ENUMX + BFD_RELOC_16C_IMM04_C +ENUMX + BFD_RELOC_16C_IMM16 +ENUMX + BFD_RELOC_16C_IMM16_C +ENUMX + BFD_RELOC_16C_IMM20 +ENUMX + BFD_RELOC_16C_IMM20_C +ENUMX + BFD_RELOC_16C_IMM24 +ENUMX + BFD_RELOC_16C_IMM24_C +ENUMX + BFD_RELOC_16C_IMM32 +ENUMX + BFD_RELOC_16C_IMM32_C +ENUMDOC + NS CR16C Relocations. + +ENUM + BFD_RELOC_CRX_REL4 +ENUMX + BFD_RELOC_CRX_REL8 +ENUMX + BFD_RELOC_CRX_REL8_CMP +ENUMX + BFD_RELOC_CRX_REL16 +ENUMX + BFD_RELOC_CRX_REL24 +ENUMX + BFD_RELOC_CRX_REL32 +ENUMX + BFD_RELOC_CRX_REGREL12 +ENUMX + BFD_RELOC_CRX_REGREL22 +ENUMX + BFD_RELOC_CRX_REGREL28 +ENUMX + BFD_RELOC_CRX_REGREL32 +ENUMX + BFD_RELOC_CRX_ABS16 +ENUMX + BFD_RELOC_CRX_ABS32 +ENUMX + BFD_RELOC_CRX_NUM8 +ENUMX + BFD_RELOC_CRX_NUM16 +ENUMX + BFD_RELOC_CRX_NUM32 +ENUMX + BFD_RELOC_CRX_IMM16 +ENUMX + BFD_RELOC_CRX_IMM32 +ENUMX + BFD_RELOC_CRX_SWITCH8 +ENUMX + BFD_RELOC_CRX_SWITCH16 +ENUMX + BFD_RELOC_CRX_SWITCH32 +ENUMDOC + NS CRX Relocations. + +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_SIGNED_8 +ENUMX + BFD_RELOC_CRIS_UNSIGNED_8 +ENUMX + BFD_RELOC_CRIS_SIGNED_16 +ENUMX + BFD_RELOC_CRIS_UNSIGNED_16 +ENUMX + BFD_RELOC_CRIS_LAPCQ_OFFSET +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_XC16X_PAG +ENUMX + BFD_RELOC_XC16X_POF +ENUMX + BFD_RELOC_XC16X_SEG +ENUMX + BFD_RELOC_XC16X_SOF +ENUMDOC + Infineon 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_MT_PC16 +ENUMDOC + Morpho MT - 16 bit immediate relocation. +ENUM + BFD_RELOC_MT_HI16 +ENUMDOC + Morpho MT - Hi 16 bits of an address. +ENUM + BFD_RELOC_MT_LO16 +ENUMDOC + Morpho MT - Low 16 bits of an address. +ENUM + BFD_RELOC_MT_GNU_VTINHERIT +ENUMDOC + Morpho MT - Used to tell the linker which vtable entries are used. +ENUM + BFD_RELOC_MT_GNU_VTENTRY +ENUMDOC + Morpho MT - Used to tell the linker which vtable entries are used. +ENUM + BFD_RELOC_MT_PCINSN8 +ENUMDOC + Morpho MT - 8 bit immediate relocation. + +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 +ENUMX + BFD_RELOC_MSP430_2X_PCREL +ENUMX + BFD_RELOC_MSP430_RL_PCREL +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_DIFF8 +ENUMX + BFD_RELOC_XTENSA_DIFF16 +ENUMX + BFD_RELOC_XTENSA_DIFF32 +ENUMDOC + Xtensa relocations to mark the difference of two local symbols. + These are only needed to support linker relaxation and can be ignored + when not relaxing. The field is set to the value of the difference + assuming no relaxation. The relocation encodes the position of the + first symbol so the linker can determine whether to adjust the field + value. +ENUM + BFD_RELOC_XTENSA_SLOT0_OP +ENUMX + BFD_RELOC_XTENSA_SLOT1_OP +ENUMX + BFD_RELOC_XTENSA_SLOT2_OP +ENUMX + BFD_RELOC_XTENSA_SLOT3_OP +ENUMX + BFD_RELOC_XTENSA_SLOT4_OP +ENUMX + BFD_RELOC_XTENSA_SLOT5_OP +ENUMX + BFD_RELOC_XTENSA_SLOT6_OP +ENUMX + BFD_RELOC_XTENSA_SLOT7_OP +ENUMX + BFD_RELOC_XTENSA_SLOT8_OP +ENUMX + BFD_RELOC_XTENSA_SLOT9_OP +ENUMX + BFD_RELOC_XTENSA_SLOT10_OP +ENUMX + BFD_RELOC_XTENSA_SLOT11_OP +ENUMX + BFD_RELOC_XTENSA_SLOT12_OP +ENUMX + BFD_RELOC_XTENSA_SLOT13_OP +ENUMX + BFD_RELOC_XTENSA_SLOT14_OP +ENUMDOC + Generic Xtensa relocations for instruction operands. Only the slot + number is encoded in the relocation. The relocation applies to the + last PC-relative immediate operand, or if there are no PC-relative + immediates, to the last immediate operand. +ENUM + BFD_RELOC_XTENSA_SLOT0_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT1_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT2_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT3_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT4_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT5_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT6_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT7_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT8_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT9_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT10_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT11_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT12_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT13_ALT +ENUMX + BFD_RELOC_XTENSA_SLOT14_ALT +ENUMDOC + Alternate Xtensa relocations. Only the slot is encoded in the + relocation. The meaning of these relocations is opcode-specific. +ENUM + BFD_RELOC_XTENSA_OP0 +ENUMX + BFD_RELOC_XTENSA_OP1 +ENUMX + BFD_RELOC_XTENSA_OP2 +ENUMDOC + Xtensa relocations for backward compatibility. These have all been + replaced by BFD_RELOC_XTENSA_SLOT0_OP. +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. + +ENUM + BFD_RELOC_Z80_DISP8 +ENUMDOC + 8 bit signed offset in (ix+d) or (iy+d). + +ENUM + BFD_RELOC_Z8K_DISP7 +ENUMDOC + DJNZ offset. +ENUM + BFD_RELOC_Z8K_CALLR +ENUMDOC + CALR offset. +ENUM + BFD_RELOC_Z8K_IMM4L +ENUMDOC + 4 bit value. + +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 (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_dont, 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 (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 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 (bfd_reloc_code_real_type code) +{ + if (code > BFD_RELOC_UNUSED) + return 0; + return bfd_reloc_code_real_names[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. +*/ + +bfd_boolean +bfd_generic_relax_section (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 (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_info *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 (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 relocatable, + 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 (bfd *abfd, + struct bfd_link_info *link_info, + struct bfd_link_order *link_order, + bfd_byte *data, + bfd_boolean relocatable, + 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; + bfd_size_type sz; + + if (reloc_size < 0) + goto error_return; + + reloc_vector = bfd_malloc (reloc_size); + if (reloc_vector == NULL && reloc_size != 0) + goto error_return; + + /* Read in the section. */ + sz = input_section->rawsize ? input_section->rawsize : input_section->size; + if (!bfd_get_section_contents (input_bfd, input_section, data, 0, sz)) + goto error_return; + + reloc_count = bfd_canonicalize_reloc (input_bfd, + input_section, + reloc_vector, + symbols); + if (reloc_count < 0) + goto error_return; + + if (reloc_count > 0) + { + arelent **parent; + for (parent = reloc_vector; *parent != NULL; parent++) + { + char *error_message = NULL; + bfd_reloc_status_type r = + bfd_perform_relocation (input_bfd, + *parent, + data, + input_section, + relocatable ? abfd : NULL, + &error_message); + + if (relocatable) + { + asection *os = input_section->output_section; + + /* A partial link, so keep the relocs. */ + os->orelocation[os->reloc_count] = *parent; + os->reloc_count++; + } + + if (r != bfd_reloc_ok) + { + switch (r) + { + case bfd_reloc_undefined: + if (!((*link_info->callbacks->undefined_symbol) + (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), + input_bfd, input_section, (*parent)->address, + TRUE))) + goto error_return; + break; + case bfd_reloc_dangerous: + BFD_ASSERT (error_message != NULL); + if (!((*link_info->callbacks->reloc_dangerous) + (link_info, error_message, input_bfd, input_section, + (*parent)->address))) + goto error_return; + break; + case bfd_reloc_overflow: + if (!((*link_info->callbacks->reloc_overflow) + (link_info, NULL, + bfd_asymbol_name (*(*parent)->sym_ptr_ptr), + (*parent)->howto->name, (*parent)->addend, + input_bfd, input_section, (*parent)->address))) + goto error_return; + break; + case bfd_reloc_outofrange: + 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.17/bfd/section.c b/contrib/binutils-2.17/bfd/section.c new file mode 100644 index 0000000000..f870e6bfc0 --- /dev/null +++ b/contrib/binutils-2.17/bfd/section.c @@ -0,0 +1,1521 @@ +/* Object file "section" support for the BFD library. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004, 2005, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 +. +.typedef struct bfd_section +.{ +. {* 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 bfd_section *next; +. +. {* The previous section in the list belonging to the BFD, or NULL. *} +. struct bfd_section *prev; +. +. {* 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 +. +. {* A signal to the OS that the section contains read only data. *} +.#define SEC_READONLY 0x008 +. +. {* The section contains code only. *} +.#define SEC_CODE 0x010 +. +. {* The section contains data only. *} +.#define SEC_DATA 0x020 +. +. {* The section will reside in ROM. *} +.#define SEC_ROM 0x040 +. +. {* 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 0x080 +. +. {* The section has contents - a data section could be +. <> | <>; a debug section could be +. <> *} +.#define SEC_HAS_CONTENTS 0x100 +. +. {* An instruction to the linker to not output the section +. even if it has information which would normally be written. *} +.#define SEC_NEVER_LOAD 0x200 +. +. {* The section contains thread local data. *} +.#define SEC_THREAD_LOCAL 0x400 +. +. {* 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 0x800 +. +. {* 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 0x1000 +. +. {* 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 0x2000 +. +. {* 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 0x4000 +. +. {* 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 0x8000 +. +. {* 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 0x10000 +. +. {* 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 0x20000 +. +. {* If SEC_LINK_ONCE is set, this bitfield describes how the linker +. should handle duplicate sections. *} +.#define SEC_LINK_DUPLICATES 0x40000 +. +. {* 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 0x80000 +. +. {* 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 0x100000 +. +. {* 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 \ +. (SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE) +. +. {* 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 0x200000 +. +. {* This section should not be subject to garbage collection. *} +.#define SEC_KEEP 0x400000 +. +. {* This section contains "short" data, and should be placed +. "near" the GP. *} +.#define SEC_SMALL_DATA 0x800000 +. +. {* Attempt to merge identical entities in the section. +. Entity size is given in the entsize field. *} +.#define SEC_MERGE 0x1000000 +. +. {* 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 0x2000000 +. +. {* This section contains data about section groups. *} +.#define SEC_GROUP 0x4000000 +. +. {* 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 0x10000000 +. +. {* This section contains data which may be shared with other +. executables or shared objects. This is for COFF only. *} +.#define SEC_COFF_SHARED 0x20000000 +. +. {* 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. This is for TI +. TMS320C54X only. *} +.#define SEC_TIC54X_BLOCK 0x40000000 +. +. {* Conditionally link this section; do not link if there are no +. references found to any symbol in the section. This is for TI +. TMS320C54X only. *} +.#define SEC_TIC54X_CLINK 0x80000000 +. +. {* End of section flags. *} +. +. {* Some internal packed boolean fields. *} +. +. {* See the vma field. *} +. unsigned int user_set_vma : 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; +. +. {* Mark flags used by some linker backends for garbage collection. *} +. unsigned int gc_mark : 1; +. unsigned int gc_mark_from_eh : 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. The generic code doesn't touch +. these fields. *} +. +. {* Nonzero if this section has TLS related relocations. *} +. unsigned int has_tls_reloc:1; +. +. {* Nonzero if this section has a gp reloc. *} +. unsigned int has_gp_reloc:1; +. +. {* Nonzero if this section needs the relax finalize pass. *} +. unsigned int need_finalize_relax:1; +. +. {* Whether relocations have been processed. *} +. unsigned int reloc_done : 1; +. +. {* 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>>). *} +. bfd_size_type size; +. +. {* For input sections, the original size on disk of the section, in +. octets. This field is used by the linker relaxation code. It is +. currently only set for sections where the linker relaxation scheme +. doesn't cache altered section and reloc contents (stabs, eh_frame, +. SEC_MERGE, some coff relaxing targets), and thus the original size +. needs to be kept to read the section multiple times. +. For output sections, rawsize holds the section size calculated on +. a previous linker relaxation pass. *} +. bfd_size_type rawsize; +. +. {* 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 bfd_section *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. *} +. void *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; +. +. {* Points to the kept section if this section is a link-once section, +. and is discarded. *} +. struct bfd_section *kept_section; +. +. {* 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; +. +. void *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 bfd_symbol *symbol; +. struct bfd_symbol **symbol_ptr_ptr; +. +. {* Early in the link process, map_head and map_tail are used to build +. a list of input sections attached to an output section. Later, +. output sections use these fields for a list of bfd_link_order +. structs. *} +. union { +. struct bfd_link_order *link_order; +. struct bfd_section *s; +. } map_head, map_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 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 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 asection bfd_com_section; +.#define bfd_com_section_ptr ((asection *) &bfd_com_section) +.{* Pointer to the indirect section. *} +.extern 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 bfd_symbol * const bfd_abs_symbol; +.extern const struct bfd_symbol * const bfd_com_symbol; +.extern const struct bfd_symbol * const bfd_und_symbol; +.extern const struct bfd_symbol * const bfd_ind_symbol; +. +.{* 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, S) \ +. do \ +. { \ +. asection *_s = S; \ +. asection *_next = _s->next; \ +. asection *_prev = _s->prev; \ +. if (_prev) \ +. _prev->next = _next; \ +. else \ +. (ABFD)->sections = _next; \ +. if (_next) \ +. _next->prev = _prev; \ +. else \ +. (ABFD)->section_last = _prev; \ +. } \ +. while (0) +.#define bfd_section_list_append(ABFD, S) \ +. do \ +. { \ +. asection *_s = S; \ +. bfd *_abfd = ABFD; \ +. _s->next = NULL; \ +. if (_abfd->section_last) \ +. { \ +. _s->prev = _abfd->section_last; \ +. _abfd->section_last->next = _s; \ +. } \ +. else \ +. { \ +. _s->prev = NULL; \ +. _abfd->sections = _s; \ +. } \ +. _abfd->section_last = _s; \ +. } \ +. while (0) +.#define bfd_section_list_prepend(ABFD, S) \ +. do \ +. { \ +. asection *_s = S; \ +. bfd *_abfd = ABFD; \ +. _s->prev = NULL; \ +. if (_abfd->sections) \ +. { \ +. _s->next = _abfd->sections; \ +. _abfd->sections->prev = _s; \ +. } \ +. else \ +. { \ +. _s->next = NULL; \ +. _abfd->section_last = _s; \ +. } \ +. _abfd->sections = _s; \ +. } \ +. while (0) +.#define bfd_section_list_insert_after(ABFD, A, S) \ +. do \ +. { \ +. asection *_a = A; \ +. asection *_s = S; \ +. asection *_next = _a->next; \ +. _s->next = _next; \ +. _s->prev = _a; \ +. _a->next = _s; \ +. if (_next) \ +. _next->prev = _s; \ +. else \ +. (ABFD)->section_last = _s; \ +. } \ +. while (0) +.#define bfd_section_list_insert_before(ABFD, B, S) \ +. do \ +. { \ +. asection *_b = B; \ +. asection *_s = S; \ +. asection *_prev = _b->prev; \ +. _s->prev = _prev; \ +. _s->next = _b; \ +. _b->prev = _s; \ +. if (_prev) \ +. _prev->next = _s; \ +. else \ +. (ABFD)->sections = _s; \ +. } \ +. while (0) +.#define bfd_section_removed_from_list(ABFD, S) \ +. ((S)->next == NULL ? (ABFD)->section_last != (S) : (S)->next->prev != (S)) +. +.#define BFD_FAKE_SECTION(SEC, FLAGS, SYM, SYM_PTR, NAME, IDX) \ +. {* name, id, index, next, prev, flags, user_set_vma, *} \ +. { NAME, IDX, 0, NULL, NULL, FLAGS, 0, \ +. \ +. {* linker_mark, linker_has_input, gc_mark, gc_mark_from_eh, *} \ +. 0, 0, 1, 0, \ +. \ +. {* segment_mark, sec_info_type, use_rela_p, has_tls_reloc, *} \ +. 0, 0, 0, 0, \ +. \ +. {* has_gp_reloc, need_finalize_relax, reloc_done, *} \ +. 0, 0, 0, \ +. \ +. {* vma, lma, size, rawsize *} \ +. 0, 0, 0, 0, \ +. \ +. {* output_offset, output_section, alignment_power, *} \ +. 0, (struct bfd_section *) &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, kept_section, moving_line_filepos, *} \ +. 0, NULL, 0, \ +. \ +. {* target_index, used_by_bfd, constructor_chain, owner, *} \ +. 0, NULL, NULL, NULL, \ +. \ +. {* symbol, *} \ +. (struct bfd_symbol *) SYM, \ +. \ +. {* symbol_ptr_ptr, *} \ +. (struct bfd_symbol **) SYM_PTR, \ +. \ +. {* map_head, map_tail *} \ +. { NULL }, { NULL } \ +. } +. +*/ + +/* 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]; \ + asection SEC = BFD_FAKE_SECTION(SEC, FLAGS, &global_syms[IDX], &SYM, \ + NAME, IDX) + +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 + +/* Initialize an entry in the section hash table. */ + +struct bfd_hash_entry * +bfd_section_hash_newfunc (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 (&((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 (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++; + bfd_section_list_append (abfd, newsect); + 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 (bfd *abfd) +{ + abfd->sections = NULL; + abfd->section_last = NULL; + abfd->section_count = 0; + memset (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 (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_section_by_name_if + +SYNOPSIS + asection *bfd_get_section_by_name_if + (bfd *abfd, + const char *name, + bfd_boolean (*func) (bfd *abfd, asection *sect, void *obj), + void *obj); + +DESCRIPTION + Call the provided function @var{func} for each section + attached to the BFD @var{abfd} whose name matches @var{name}, + passing @var{obj} as an argument. The function will be called + as if by + +| func (abfd, the_section, obj); + + It returns the first section for which @var{func} returns true, + otherwise <>. + +*/ + +asection * +bfd_get_section_by_name_if (bfd *abfd, const char *name, + bfd_boolean (*operation) (bfd *, + asection *, + void *), + void *user_storage) +{ + struct section_hash_entry *sh; + unsigned long hash; + + sh = section_hash_lookup (&abfd->section_htab, name, FALSE, FALSE); + if (sh == NULL) + return NULL; + + hash = sh->root.hash; + do + { + if ((*operation) (abfd, &sh->section, user_storage)) + return &sh->section; + sh = (struct section_hash_entry *) sh->root.next; + } + while (sh != NULL && sh->root.hash == hash + && strcmp (sh->root.string, name) == 0); + + 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 (bfd *abfd, const char *templat, int *count) +{ + int num; + unsigned int len; + char *sname; + + len = strlen (templat); + sname = bfd_malloc (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 (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_with_flags + +SYNOPSIS + asection *bfd_make_section_anyway_with_flags + (bfd *abfd, const char *name, flagword flags); + +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. Also set the attributes of the + new section to the value @var{flags}. + + 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_with_flags (bfd *abfd, const char *name, + flagword flags) +{ + 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. Put it in the + section hash table. Even though we can't find it directly by a + hash lookup, we'll be able to find the section by traversing + sh->root.next quicker than looking at all the bfd sections. */ + struct section_hash_entry *new_sh; + new_sh = (struct section_hash_entry *) + bfd_section_hash_newfunc (NULL, &abfd->section_htab, name); + if (new_sh == NULL) + return NULL; + + new_sh->root = sh->root; + sh->root.next = &new_sh->root; + newsect = &new_sh->section; + } + + newsect->flags = flags; + 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 (bfd *abfd, const char *name) +{ + return bfd_make_section_anyway_with_flags (abfd, name, 0); +} + +/* +FUNCTION + bfd_make_section_with_flags + +SYNOPSIS + asection *bfd_make_section_with_flags + (bfd *, const char *name, flagword flags); + +DESCRIPTION + Like <>, but return <> (without calling + bfd_set_error ()) without changing the section chain if there is already a + section named @var{name}. Also set the attributes of the new section to + the value @var{flags}. If there is an error, return <> and set + <>. +*/ + +asection * +bfd_make_section_with_flags (bfd *abfd, const char *name, + flagword flags) +{ + 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 NULL; + } + + newsect->name = name; + newsect->flags = flags; + 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 (bfd *abfd, const char *name) +{ + return bfd_make_section_with_flags (abfd, name, 0); +} + +/* +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. + +*/ + +bfd_boolean +bfd_set_section_flags (bfd *abfd ATTRIBUTE_UNUSED, + sec_ptr section, + flagword flags) +{ + section->flags = flags; + return TRUE; +} + +/* +FUNCTION + bfd_map_over_sections + +SYNOPSIS + void bfd_map_over_sections + (bfd *abfd, + void (*func) (bfd *abfd, asection *sect, void *obj), + void *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 preferred 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, ...) + +*/ + +void +bfd_map_over_sections (bfd *abfd, + void (*operation) (bfd *, asection *, void *), + void *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_sections_find_if + +SYNOPSIS + asection *bfd_sections_find_if + (bfd *abfd, + bfd_boolean (*operation) (bfd *abfd, asection *sect, void *obj), + void *obj); + +DESCRIPTION + Call the provided function @var{operation} for each section + attached to the BFD @var{abfd}, passing @var{obj} as an + argument. The function will be called as if by + +| operation (abfd, the_section, obj); + + It returns the first section for which @var{operation} returns true. + +*/ + +asection * +bfd_sections_find_if (bfd *abfd, + bfd_boolean (*operation) (bfd *, asection *, void *), + void *user_storage) +{ + asection *sect; + + for (sect = abfd->sections; sect != NULL; sect = sect->next) + if ((*operation) (abfd, sect, user_storage)) + break; + + return sect; +} + +/* +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 (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->size = val; + return TRUE; +} + +/* +FUNCTION + bfd_set_section_contents + +SYNOPSIS + bfd_boolean bfd_set_section_contents + (bfd *abfd, asection *section, const void *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>>. + +*/ + +bfd_boolean +bfd_set_section_contents (bfd *abfd, + sec_ptr section, + const void *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 = section->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 (!bfd_write_p (abfd)) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + /* Record a copy of the data in memory if desired. */ + if (section->contents + && location != 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, void *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 (bfd *abfd, + sec_ptr section, + void *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; + } + + sz = section->rawsize ? section->rawsize : section->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_malloc_and_get_section + +SYNOPSIS + bfd_boolean bfd_malloc_and_get_section + (bfd *abfd, asection *section, bfd_byte **buf); + +DESCRIPTION + Read all data from @var{section} in BFD @var{abfd} + into a buffer, *@var{buf}, malloc'd by this function. +*/ + +bfd_boolean +bfd_malloc_and_get_section (bfd *abfd, sec_ptr sec, bfd_byte **buf) +{ + bfd_size_type sz = sec->rawsize ? sec->rawsize : sec->size; + bfd_byte *p = NULL; + + *buf = p; + if (sz == 0) + return TRUE; + + p = bfd_malloc (sec->rawsize > sec->size ? sec->rawsize : sec->size); + if (p == NULL) + return FALSE; + *buf = p; + + return bfd_get_section_contents (abfd, sec, p, 0, sz); +} +/* +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_generic_is_group_section + +SYNOPSIS + bfd_boolean bfd_generic_is_group_section (bfd *, const asection *sec); + +DESCRIPTION + Returns TRUE if @var{sec} is a member of a group. +*/ + +bfd_boolean +bfd_generic_is_group_section (bfd *abfd ATTRIBUTE_UNUSED, + const asection *sec ATTRIBUTE_UNUSED) +{ + return FALSE; +} + +/* +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 (bfd *abfd ATTRIBUTE_UNUSED, + asection *group ATTRIBUTE_UNUSED) +{ + return TRUE; +} diff --git a/contrib/binutils-2.17/bfd/simple.c b/contrib/binutils-2.17/bfd/simple.c new file mode 100644 index 0000000000..d06ce2a96e --- /dev/null +++ b/contrib/binutils-2.17/bfd/simple.c @@ -0,0 +1,257 @@ +/* simple.c -- BFD simple client routines + Copyright 2002, 2003, 2004, 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "bfdlink.h" + +static bfd_boolean +simple_dummy_warning (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 (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 (struct bfd_link_info *link_info ATTRIBUTE_UNUSED, + struct bfd_link_hash_entry *entry 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 (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 (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; +} + +static bfd_boolean +simple_dummy_multiple_definition (struct bfd_link_info *link_info ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED, + bfd *obfd ATTRIBUTE_UNUSED, + asection *osec ATTRIBUTE_UNUSED, + bfd_vma oval ATTRIBUTE_UNUSED, + bfd *nbfd ATTRIBUTE_UNUSED, + asection *nsec ATTRIBUTE_UNUSED, + bfd_vma nval ATTRIBUTE_UNUSED) +{ + return TRUE; +} + +static void +simple_dummy_einfo (const char *fmt ATTRIBUTE_UNUSED, ...) +{ +} + +struct saved_output_info +{ + bfd_vma offset; + asection *section; +}; + +static void +simple_save_output_info (bfd *abfd ATTRIBUTE_UNUSED, + asection *section, + void *ptr) +{ + struct saved_output_info *output_info = ptr; + output_info[section->index].offset = section->output_offset; + output_info[section->index].section = section->output_section; + if ((section->flags & SEC_DEBUGGING) != 0 + || section->output_section == NULL) + { + section->output_offset = 0; + section->output_section = section; + } +} + +static void +simple_restore_output_info (bfd *abfd ATTRIBUTE_UNUSED, + asection *section, + void *ptr) +{ + struct saved_output_info *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 debug 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}. + + Returns @code{NULL} on a fatal error; ignores errors applying + particular relocations. +*/ + +bfd_byte * +bfd_simple_get_relocated_section_contents (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; + void *saved_offsets; + + if (! (sec->flags & SEC_RELOC)) + { + bfd_size_type amt = sec->rawsize > sec->size ? sec->rawsize : sec->size; + bfd_size_type size = sec->rawsize ? sec->rawsize : sec->size; + + if (outbuf == NULL) + contents = bfd_malloc (amt); + 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_generic_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; + callbacks.multiple_definition = simple_dummy_multiple_definition; + callbacks.einfo = simple_dummy_einfo; + + 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 = sec->size; + link_order.u.indirect.section = sec; + + data = NULL; + if (outbuf == NULL) + { + data = bfd_malloc (sec->size); + 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 emitting + 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_generic_link_add_symbols (abfd, &link_info); + + storage_needed = bfd_get_symtab_upper_bound (abfd); + symbol_table = 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); + + bfd_map_over_sections (abfd, simple_restore_output_info, saved_offsets); + free (saved_offsets); + + _bfd_generic_link_hash_table_free (link_info.hash); + return contents; +} diff --git a/contrib/binutils-2.17/bfd/srec.c b/contrib/binutils-2.17/bfd/srec.c new file mode 100644 index 0000000000..2b24f46ffb --- /dev/null +++ b/contrib/binutils-2.17/bfd/srec.c @@ -0,0 +1,1322 @@ +/* BFD back-end for s-record objects. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004, 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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" + + +/* 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) + +/* 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; + +/* Initialize by filling in the hex conversion array. */ + +static void +srec_init (void) +{ + static bfd_boolean inited = FALSE; + + if (! inited) + { + inited = TRUE; + hex_init (); + } +} + +/* Set up the S-record tdata information. */ + +static bfd_boolean +srec_mkobject (bfd *abfd) +{ + tdata_type *tdata; + + srec_init (); + + tdata = bfd_alloc (abfd, sizeof (tdata_type)); + 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 (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 (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) + (_("%B:%d: Unexpected character `%s' in S-record file\n"), + 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 (bfd *abfd, const char *name, bfd_vma val) +{ + struct srec_symbol *n; + + n = bfd_alloc (abfd, sizeof (* n)); + 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 (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 = 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 = 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_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->size == address) + { + /* This data goes at the end of the section we are + currently building. */ + sec->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 = 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->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 (bfd *abfd) +{ + void * 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 (bfd *abfd) +{ + void * 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 (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_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->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->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->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 (bfd *abfd, + asection *section, + void * location, + file_ptr offset, + bfd_size_type count) +{ + if (section->used_by_bfd == NULL) + { + section->used_by_bfd = bfd_alloc (abfd, section->size); + if (section->used_by_bfd == NULL && section->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 (bfd *abfd, enum bfd_architecture arch, unsigned long mach) +{ + if (arch != bfd_arch_unknown) + return bfd_default_set_arch_mach (abfd, arch, mach); + + abfd->arch_info = & bfd_default_arch_struct; + return TRUE; +} + +/* We have to save up all the Srecords for a splurge before output. */ + +static bfd_boolean +srec_set_section_contents (bfd *abfd, + sec_ptr section, + const void * location, + file_ptr offset, + bfd_size_type bytes_to_do) +{ + tdata_type *tdata = abfd->tdata.srec_data; + srec_data_list_type *entry; + + entry = bfd_alloc (abfd, sizeof (* entry)); + if (entry == NULL) + return FALSE; + + if (bytes_to_do + && (section->flags & SEC_ALLOC) + && (section->flags & SEC_LOAD)) + { + bfd_byte *data; + + data = bfd_alloc (abfd, bytes_to_do); + if (data == NULL) + return FALSE; + memcpy ((void *) 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 + { + 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 (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; + + return bfd_bwrite ((void *) buffer, wrlen, abfd) == wrlen; +} + +static bfd_boolean +srec_write_header (bfd *abfd) +{ + unsigned int len = strlen (abfd->filename); + + /* I'll put an arbitrary 40 char limit on header size. */ + if (len > 40) + len = 40; + + return srec_write_record (abfd, 0, (bfd_vma) 0, + (bfd_byte *) abfd->filename, + (bfd_byte *) abfd->filename + len); +} + +static bfd_boolean +srec_write_section (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 (bfd *abfd, tdata_type *tdata) +{ + return srec_write_record (abfd, 10 - tdata->type, + abfd->start_address, NULL, NULL); +} + +static bfd_boolean +srec_write_symbols (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 (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 (bfd *abfd) +{ + return internal_srec_write_object_contents (abfd, 0); +} + +static bfd_boolean +symbolsrec_write_object_contents (bfd *abfd) +{ + return internal_srec_write_object_contents (abfd, 1); +} + +static int +srec_sizeof_headers (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 (bfd *abfd) +{ + return (bfd_get_symcount (abfd) + 1) * sizeof (asymbol *); +} + +/* Return the symbol table. */ + +static long +srec_canonicalize_symtab (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 = 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 (bfd *ignore_abfd ATTRIBUTE_UNUSED, + asymbol *symbol, + symbol_info *ret) +{ + bfd_symbol_info (symbol, ret); +} + +static void +srec_print_symbol (bfd *abfd, + void * 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, (void *) 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_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) +#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_find_inliner_info _bfd_nosymbols_find_inliner_info +#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 (*) (bfd *, asection *)) bfd_0l) +#define srec_canonicalize_reloc ((long (*) (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_is_group_section bfd_generic_is_group_section +#define srec_bfd_discard_group bfd_generic_discard_group +#define srec_section_already_linked _bfd_generic_section_already_linked +#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, + + NULL +}; + +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, /* Headers. */ + + { + _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, + + NULL +}; diff --git a/contrib/binutils-2.17/bfd/stab-syms.c b/contrib/binutils-2.17/bfd/stab-syms.c new file mode 100644 index 0000000000..c577e1f417 --- /dev/null +++ b/contrib/binutils-2.17/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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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.17/bfd/stabs.c b/contrib/binutils-2.17/bfd/stabs.c new file mode 100644 index 0000000000..ba3f934461 --- /dev/null +++ b/contrib/binutils-2.17/bfd/stabs.c @@ -0,0 +1,784 @@ +/* Stabs in sections linking support. + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, + 2006 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 linked list of totals that we have found for a particular header + file. A total is a unique identifier for a particular BINCL...EINCL + sequence of STABs that can be used to identify duplicate sequences. + It consists of three fields, 'sum_chars' which is the sum of all the + STABS characters; 'num_chars' which is the number of these charactes + and 'symb' which is a buffer of all the symbols in the sequence. This + buffer is only checked as a last resort. */ + +struct stab_link_includes_totals +{ + struct stab_link_includes_totals *next; + bfd_vma sum_chars; /* Accumulated sum of STABS characters. */ + bfd_vma num_chars; /* Number of STABS characters. */ + const char* symb; /* The STABS characters themselves. */ +}; + +/* 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; +}; + +/* 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]; +}; + + +/* The function to create a new entry in the header file hash table. */ + +static struct bfd_hash_entry * +stab_link_includes_newfunc (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 == NULL) + ret = bfd_hash_allocate (table, + sizeof (struct stab_link_includes_entry)); + if (ret == NULL) + return NULL; + + /* 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 (bfd *abfd, + struct stab_info *sinfo, + asection *stabsec, + asection *stabstrsec, + void * *psecinfo, + bfd_size_type *pstring_offset) +{ + bfd_boolean first; + 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->size == 0 + || stabstrsec->size == 0) + /* This file does not contain stabs debugging information. */ + return TRUE; + + if (stabsec->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 (sinfo->stabstr == NULL) + { + /* Initialize the stabs information we need to keep track of. */ + first = TRUE; + 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 (&sinfo->includes, + stab_link_includes_newfunc, + sizeof (struct stab_link_includes_entry))) + goto error_return; + sinfo->stabstr = bfd_make_section_anyway (abfd, ".stabstr"); + if (sinfo->stabstr == NULL) + goto error_return; + sinfo->stabstr->flags |= (SEC_HAS_CONTENTS | SEC_READONLY + | SEC_DEBUGGING | SEC_LINKER_CREATED); + } + + /* Initialize the information we are going to store for this .stab + section. */ + count = stabsec->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; + stabsec->rawsize = stabsec->size; + secinfo->cumulative_skips = NULL; + memset (secinfo->stridxs, 0, (size_t) count * sizeof (bfd_size_type)); + + /* Read the stabs information from abfd. */ + if (!bfd_malloc_and_get_section (abfd, stabsec, &stabbuf) + || !bfd_malloc_and_get_section (abfd, stabstrsec, &stabstrbuf)) + 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; + /* The stabs sections can be split when + -split-by-reloc/-split-by-file is used. We must keep track of + each stab section's place in the single concatenated string + table. */ + next_stroff = pstring_offset ? *pstring_offset : 0; + skip = 0; + + symend = stabbuf + stabsec->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 (pstring_offset) + *pstring_offset = next_stroff; + 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->size) + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx): Stabs entry has invalid string index."), + 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 sum_chars; + bfd_vma num_chars; + bfd_vma buf_len = 0; + char * symb; + char * symb_rover; + int nest; + bfd_byte * incl_sym; + struct stab_link_includes_entry * incl_entry; + struct stab_link_includes_totals * t; + struct stab_excl_list * ne; + + symb = symb_rover = NULL; + sum_chars = num_chars = 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_EXCL) + continue; + 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++) + { + if (num_chars >= buf_len) + { + buf_len += 32 * 1024; + symb = bfd_realloc (symb, buf_len); + if (symb == NULL) + goto error_return; + symb_rover = symb + num_chars; + } + * symb_rover ++ = * str; + sum_chars += *str; + num_chars ++; + if (*str == '(') + { + /* Skip the file number. */ + ++str; + while (ISDIGIT (*str)) + ++str; + --str; + } + } + } + } + + BFD_ASSERT (num_chars == (bfd_vma) (symb_rover - symb)); + + /* If we have already included a header file with the same + value, then replaced this one with an N_EXCL symbol. */ + incl_entry = (struct stab_link_includes_entry * ) + bfd_hash_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->sum_chars == sum_chars + && t->num_chars == num_chars + && memcmp (t->symb, symb, num_chars) == 0) + break; + + /* Record this symbol, so that we can set the value + correctly. */ + amt = sizeof *ne; + ne = bfd_alloc (abfd, amt); + if (ne == NULL) + goto error_return; + ne->offset = sym - stabbuf; + ne->val = sum_chars; + 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 = bfd_hash_allocate (&sinfo->includes, sizeof *t); + if (t == NULL) + goto error_return; + t->sum_chars = sum_chars; + t->num_chars = num_chars; + t->symb = bfd_realloc (symb, num_chars); /* Trim data down. */ + 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; + + /* Free off superfluous symbols. */ + free (symb); + + /* 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 (incl_type == (int) N_EXCL) + /* Keep existing exclusion marks. */ + continue; + 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->size = (count - skip) * STABSIZE; + if (stabsec->size == 0) + stabsec->flags |= SEC_EXCLUDE; + stabstrsec->flags |= SEC_EXCLUDE; + sinfo->stabstr->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_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 (bfd *abfd, + asection *stabsec, + void * psecinfo, + bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *), + void * 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->size == 0) + /* This file does not contain stabs debugging information. */ + return FALSE; + + if (stabsec->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->rawsize / STABSIZE; + secinfo = (struct stab_section_info *) psecinfo; + + /* Read the stabs information from abfd. */ + if (!bfd_malloc_and_get_section (abfd, stabsec, &stabbuf)) + goto error_return; + + /* Look through the stabs symbols and discard any information for + discarded functions. */ + skip = 0; + deleting = -1; + + symend = stabbuf + stabsec->rawsize; + 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->size -= skip * STABSIZE; + if (stabsec->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_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 (bfd *output_bfd, + struct stab_info *sinfo, + asection *stabsec, + void * *psecinfo, + bfd_byte *contents) +{ + struct stab_section_info *secinfo; + struct stab_excl_list *e; + bfd_byte *sym, *tosym, *symend; + bfd_size_type *pstridx; + + secinfo = (struct stab_section_info *) *psecinfo; + + if (secinfo == NULL) + return bfd_set_section_contents (output_bfd, stabsec->output_section, + contents, stabsec->output_offset, + stabsec->size); + + /* Handle each N_BINCL entry. */ + for (e = secinfo->excls; e != NULL; e = e->next) + { + bfd_byte *excl_sym; + + BFD_ASSERT (e->offset < stabsec->rawsize); + 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->rawsize; + 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->size / STABSIZE - 1, + tosym + DESCOFF); + } + + tosym += STABSIZE; + } + } + + BFD_ASSERT ((bfd_size_type) (tosym - contents) == stabsec->size); + + return bfd_set_section_contents (output_bfd, stabsec->output_section, + contents, (file_ptr) stabsec->output_offset, + stabsec->size); +} + +/* Write out the .stabstr section. */ + +bfd_boolean +_bfd_write_stab_strings (bfd *output_bfd, struct stab_info *sinfo) +{ + 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->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); + + 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 (asection *stabsec, + void * psecinfo, + bfd_vma offset) +{ + struct stab_section_info *secinfo; + + secinfo = (struct stab_section_info *) psecinfo; + + if (secinfo == NULL) + return offset; + + if (offset >= stabsec->rawsize) + return offset - stabsec->rawsize + stabsec->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.17/bfd/syms.c b/contrib/binutils-2.17/bfd/syms.c new file mode 100644 index 0000000000..0ff94164ed --- /dev/null +++ b/contrib/binutils-2.17/bfd/syms.c @@ -0,0 +1,1391 @@ +/* Generic symbol-table support for the BFD library. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 = 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] = 0; +| +| bfd_set_symtab (abfd, ptrs, 1); +| bfd_close (abfd); +| return 0; +| } +| +| ./makesym +| nm foo +| 00012345 A dummy_symbol + + Many formats cannot represent arbitrary symbol information; for + instance, the <> object format does not allow an + arbitrary 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 bfd_symbol +.{ +. {* 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 arbitrary +. 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 bfd_section *section; +. +. {* Back end special data. *} +. union +. { +. void *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" + +/* +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 (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_FILE | 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_is_target_special_symbol + +SYNOPSIS + bfd_boolean bfd_is_target_special_symbol (bfd *abfd, asymbol *sym); + +DESCRIPTION + Return TRUE iff a symbol @var{sym} in the BFD @var{abfd} is something + special to the particular target represented by the BFD. Such symbols + should normally not be mentioned to the user. + +.#define bfd_is_target_special_symbol(abfd, sym) \ +. BFD_SEND (abfd, _bfd_is_target_special_symbol, (abfd, sym)) +. +*/ + +/* +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 (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, void *file, asymbol *symbol); + +DESCRIPTION + Print the value and flags of the @var{symbol} supplied to the + stream @var{file}. +*/ +void +bfd_print_symbol_vandf (bfd *abfd, void *arg, asymbol *symbol) +{ + FILE *file = arg; + + flagword type = symbol->flags; + + if (symbol->section != 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 (bfd *abfd) +{ + bfd_size_type amt = sizeof (asymbol); + asymbol *new = 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 (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 (const struct bfd_section *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'; + if ((section->flags & SEC_HAS_CONTENTS) && (section->flags & SEC_READONLY)) + 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 (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 (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 (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 (bfd *abfd, + bfd_boolean dynamic, + void **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 = bfd_malloc (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 = 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 (bfd *abfd ATTRIBUTE_UNUSED, + bfd_boolean dynamic ATTRIBUTE_UNUSED, + const void *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 (const void *a, const void *b) +{ + const struct indexentry *contestantA = a; + const struct indexentry *contestantB = 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 (bfd *abfd, + asymbol **symbols, + asection *section, + bfd_vma offset, + bfd_boolean *pfound, + const char **pfilename, + const char **pfnname, + unsigned int *pline, + void **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 = *pinfo; + if (info != NULL) + { + if (info->stabsec == NULL || info->strsec == NULL) + { + /* No stabs debugging information. */ + return TRUE; + } + + stabsize = (info->stabsec->rawsize + ? info->stabsec->rawsize + : info->stabsec->size); + strsize = (info->strsec->rawsize + ? info->strsec->rawsize + : info->strsec->size); + } + else + { + long reloc_size, reloc_count; + arelent **reloc_vector; + int i; + char *name; + char *function_name; + bfd_size_type amt = sizeof *info; + + 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 = info; + return TRUE; + } + + stabsize = (info->stabsec->rawsize + ? info->stabsec->rawsize + : info->stabsec->size); + strsize = (info->strsec->rawsize + ? info->strsec->rawsize + : info->strsec->size); + + info->stabs = bfd_alloc (abfd, stabsize); + info->strs = bfd_alloc (abfd, strsize); + if (info->stabs == NULL || info->strs == NULL) + return FALSE; + + if (! bfd_get_section_contents (abfd, info->stabsec, info->stabs, + 0, stabsize) + || ! bfd_get_section_contents (abfd, info->strsec, info->strs, + 0, strsize)) + return FALSE; + + /* If this is a relocatable 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 = bfd_malloc (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; + /* Ignore R_*_NONE relocs. */ + if (r->howto->dst_mask == 0) + continue; + + 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 = 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 = 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-existent 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 = bfd_malloc (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.17/bfd/sysdep.h b/contrib/binutils-2.17/bfd/sysdep.h new file mode 100644 index 0000000000..f6313d3905 --- /dev/null +++ b/contrib/binutils-2.17/bfd/sysdep.h @@ -0,0 +1,201 @@ +/* sysdep.h -- handle host dependencies for the BFD library + Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 STRING_WITH_STRINGS +#include +#include +#else +#ifdef HAVE_STRING_H +#include +#else +#ifdef HAVE_STRINGS_H +#include +#else +extern char *strchr (); +extern char *strrchr (); +#endif +#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" + +#if !HAVE_DECL_FFS +extern int ffs (int); +#endif + +#if !HAVE_DECL_FREE +extern void free (); +#endif + +#if !HAVE_DECL_GETENV +extern char *getenv (); +#endif + +#if !HAVE_DECL_MALLOC +extern PTR malloc (); +#endif + +#if !HAVE_DECL_REALLOC +extern PTR realloc (); +#endif + +#if !HAVE_DECL_STPCPY +extern char *stpcpy (char *__dest, const char *__src); +#endif + +#if !HAVE_DECL_STRSTR +extern char *strstr (); +#endif + +#ifdef HAVE_FTELLO +#if !HAVE_DECL_FTELLO +extern off_t ftello (FILE *stream); +#endif +#endif + +#ifdef HAVE_FTELLO64 +#if !HAVE_DECL_FTELLO64 +extern off64_t ftello64 (FILE *stream); +#endif +#endif + +#ifdef HAVE_FSEEKO +#if !HAVE_DECL_FSEEKO +extern int fseeko (FILE *stream, off_t offset, int whence); +#endif +#endif + +#ifdef HAVE_FSEEKO64 +#if !HAVE_DECL_FSEEKO64 +extern int fseeko64 (FILE *stream, off64_t offset, int whence); +#endif +#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.17/bfd/targets.c b/contrib/binutils-2.17/bfd/targets.c new file mode 100644 index 0000000000..849eb944fb --- /dev/null +++ b/contrib/binutils-2.17/bfd/targets.c @@ -0,0 +1,1425 @@ +/* Generic target-file-type support for the BFD library. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004, 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "fnmatch.h" + +/* + It's okay to see some: +#if 0 + directives in this source file, as targets.c uses them to exclude + certain BFD vectors. This comment is specially formatted to catch + users who grep for ^#if 0, so please keep it this way! +*/ + +/* +SECTION + Targets + +DESCRIPTION + Each port of BFD to a different machine requires 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 as the first argument. +. Certain other handlers could do the same. *} +. bfd_uint64_t (*bfd_getx64) (const void *); +. bfd_int64_t (*bfd_getx_signed_64) (const void *); +. void (*bfd_putx64) (bfd_uint64_t, void *); +. bfd_vma (*bfd_getx32) (const void *); +. bfd_signed_vma (*bfd_getx_signed_32) (const void *); +. void (*bfd_putx32) (bfd_vma, void *); +. bfd_vma (*bfd_getx16) (const void *); +. bfd_signed_vma (*bfd_getx_signed_16) (const void *); +. void (*bfd_putx16) (bfd_vma, void *); +. +. {* Byte swapping for the headers. *} +. bfd_uint64_t (*bfd_h_getx64) (const void *); +. bfd_int64_t (*bfd_h_getx_signed_64) (const void *); +. void (*bfd_h_putx64) (bfd_uint64_t, void *); +. bfd_vma (*bfd_h_getx32) (const void *); +. bfd_signed_vma (*bfd_h_getx_signed_32) (const void *); +. void (*bfd_h_putx32) (bfd_vma, void *); +. bfd_vma (*bfd_h_getx16) (const void *); +. bfd_signed_vma (*bfd_h_getx_signed_16) (const void *); +. void (*bfd_h_putx16) (bfd_vma, void *); +. +. {* 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]) (bfd *); +. +. {* Set the format of a file being written. *} +. bfd_boolean (*_bfd_set_format[bfd_type_end]) (bfd *); +. +. {* Write cached information into a file being written, at <>. *} +. bfd_boolean (*_bfd_write_contents[bfd_type_end]) (bfd *); +. +The general target vector. These vectors are initialized using the +BFD_JUMP_TABLE macros. +. +. {* Generic entry points. *} +.#define BFD_JUMP_TABLE_GENERIC(NAME) \ +. NAME##_close_and_cleanup, \ +. NAME##_bfd_free_cached_info, \ +. NAME##_new_section_hook, \ +. NAME##_get_section_contents, \ +. NAME##_get_section_contents_in_window +. +. {* Called when the BFD is being closed to do any necessary cleanup. *} +. bfd_boolean (*_close_and_cleanup) (bfd *); +. {* Ask the BFD to free all cached information. *} +. bfd_boolean (*_bfd_free_cached_info) (bfd *); +. {* Called when a new section is created. *} +. bfd_boolean (*_new_section_hook) (bfd *, sec_ptr); +. {* Read the contents of a section. *} +. bfd_boolean (*_bfd_get_section_contents) +. (bfd *, sec_ptr, void *, file_ptr, bfd_size_type); +. bfd_boolean (*_bfd_get_section_contents_in_window) +. (bfd *, sec_ptr, bfd_window *, file_ptr, bfd_size_type); +. +. {* Entry points to copy private data. *} +.#define BFD_JUMP_TABLE_COPY(NAME) \ +. NAME##_bfd_copy_private_bfd_data, \ +. NAME##_bfd_merge_private_bfd_data, \ +. _bfd_generic_init_private_section_data, \ +. NAME##_bfd_copy_private_section_data, \ +. NAME##_bfd_copy_private_symbol_data, \ +. NAME##_bfd_copy_private_header_data, \ +. NAME##_bfd_set_private_flags, \ +. 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) (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) (bfd *, bfd *); +. {* Called to initialize BFD private section data from one object file +. to another. *} +.#define bfd_init_private_section_data(ibfd, isec, obfd, osec, link_info) \ +. BFD_SEND (obfd, _bfd_init_private_section_data, (ibfd, isec, obfd, osec, link_info)) +. bfd_boolean (*_bfd_init_private_section_data) +. (bfd *, sec_ptr, bfd *, sec_ptr, struct bfd_link_info *); +. {* Called to copy BFD private section data from one object file +. to another. *} +. bfd_boolean (*_bfd_copy_private_section_data) +. (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) +. (bfd *, asymbol *, bfd *, asymbol *); +. {* Called to copy BFD private header data from one object file +. to another. *} +. bfd_boolean (*_bfd_copy_private_header_data) +. (bfd *, bfd *); +. {* Called to set private backend flags. *} +. bfd_boolean (*_bfd_set_private_flags) (bfd *, flagword); +. +. {* Called to print private BFD data. *} +. bfd_boolean (*_bfd_print_private_bfd_data) (bfd *, void *); +. +. {* Core file entry points. *} +.#define BFD_JUMP_TABLE_CORE(NAME) \ +. NAME##_core_file_failing_command, \ +. NAME##_core_file_failing_signal, \ +. NAME##_core_file_matches_executable_p +. +. char * (*_core_file_failing_command) (bfd *); +. int (*_core_file_failing_signal) (bfd *); +. bfd_boolean (*_core_file_matches_executable_p) (bfd *, bfd *); +. +. {* Archive entry points. *} +.#define BFD_JUMP_TABLE_ARCHIVE(NAME) \ +. NAME##_slurp_armap, \ +. NAME##_slurp_extended_name_table, \ +. NAME##_construct_extended_name_table, \ +. NAME##_truncate_arname, \ +. NAME##_write_armap, \ +. NAME##_read_ar_hdr, \ +. NAME##_openr_next_archived_file, \ +. NAME##_get_elt_at_index, \ +. NAME##_generic_stat_arch_elt, \ +. NAME##_update_armap_timestamp +. +. bfd_boolean (*_bfd_slurp_armap) (bfd *); +. bfd_boolean (*_bfd_slurp_extended_name_table) (bfd *); +. bfd_boolean (*_bfd_construct_extended_name_table) +. (bfd *, char **, bfd_size_type *, const char **); +. void (*_bfd_truncate_arname) (bfd *, const char *, char *); +. bfd_boolean (*write_armap) +. (bfd *, unsigned int, struct orl *, unsigned int, int); +. void * (*_bfd_read_ar_hdr_fn) (bfd *); +. bfd * (*openr_next_archived_file) (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) (bfd *, symindex); +. int (*_bfd_stat_arch_elt) (bfd *, struct stat *); +. bfd_boolean (*_bfd_update_armap_timestamp) (bfd *); +. +. {* Entry points used for symbols. *} +.#define BFD_JUMP_TABLE_SYMBOLS(NAME) \ +. NAME##_get_symtab_upper_bound, \ +. NAME##_canonicalize_symtab, \ +. NAME##_make_empty_symbol, \ +. NAME##_print_symbol, \ +. NAME##_get_symbol_info, \ +. NAME##_bfd_is_local_label_name, \ +. NAME##_bfd_is_target_special_symbol, \ +. NAME##_get_lineno, \ +. NAME##_find_nearest_line, \ +. _bfd_generic_find_line, \ +. NAME##_find_inliner_info, \ +. NAME##_bfd_make_debug_symbol, \ +. NAME##_read_minisymbols, \ +. NAME##_minisymbol_to_symbol +. +. long (*_bfd_get_symtab_upper_bound) (bfd *); +. long (*_bfd_canonicalize_symtab) +. (bfd *, struct bfd_symbol **); +. struct bfd_symbol * +. (*_bfd_make_empty_symbol) (bfd *); +. void (*_bfd_print_symbol) +. (bfd *, void *, struct bfd_symbol *, 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) +. (bfd *, struct bfd_symbol *, 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) (bfd *, const char *); +. bfd_boolean (*_bfd_is_target_special_symbol) (bfd *, asymbol *); +. alent * (*_get_lineno) (bfd *, struct bfd_symbol *); +. bfd_boolean (*_bfd_find_nearest_line) +. (bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, +. const char **, const char **, unsigned int *); +. bfd_boolean (*_bfd_find_line) +. (bfd *, struct bfd_symbol **, struct bfd_symbol *, +. const char **, unsigned int *); +. bfd_boolean (*_bfd_find_inliner_info) +. (bfd *, 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) +. (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) +. (bfd *, bfd_boolean, void **, 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) +. (bfd *, bfd_boolean, const void *, asymbol *); +. +. {* Routines for relocs. *} +.#define BFD_JUMP_TABLE_RELOCS(NAME) \ +. NAME##_get_reloc_upper_bound, \ +. NAME##_canonicalize_reloc, \ +. NAME##_bfd_reloc_type_lookup +. +. long (*_get_reloc_upper_bound) (bfd *, sec_ptr); +. long (*_bfd_canonicalize_reloc) +. (bfd *, sec_ptr, arelent **, struct bfd_symbol **); +. {* See documentation on reloc types. *} +. reloc_howto_type * +. (*reloc_type_lookup) (bfd *, bfd_reloc_code_real_type); +. +. {* Routines used when writing an object file. *} +.#define BFD_JUMP_TABLE_WRITE(NAME) \ +. NAME##_set_arch_mach, \ +. NAME##_set_section_contents +. +. bfd_boolean (*_bfd_set_arch_mach) +. (bfd *, enum bfd_architecture, unsigned long); +. bfd_boolean (*_bfd_set_section_contents) +. (bfd *, sec_ptr, const void *, file_ptr, bfd_size_type); +. +. {* Routines used by the linker. *} +.#define BFD_JUMP_TABLE_LINK(NAME) \ +. NAME##_sizeof_headers, \ +. NAME##_bfd_get_relocated_section_contents, \ +. NAME##_bfd_relax_section, \ +. NAME##_bfd_link_hash_table_create, \ +. NAME##_bfd_link_hash_table_free, \ +. NAME##_bfd_link_add_symbols, \ +. NAME##_bfd_link_just_syms, \ +. NAME##_bfd_final_link, \ +. NAME##_bfd_link_split_section, \ +. NAME##_bfd_gc_sections, \ +. NAME##_bfd_merge_sections, \ +. NAME##_bfd_is_group_section, \ +. NAME##_bfd_discard_group, \ +. NAME##_section_already_linked \ +. +. int (*_bfd_sizeof_headers) (bfd *, bfd_boolean); +. bfd_byte * (*_bfd_get_relocated_section_contents) +. (bfd *, struct bfd_link_info *, struct bfd_link_order *, +. bfd_byte *, bfd_boolean, struct bfd_symbol **); +. +. bfd_boolean (*_bfd_relax_section) +. (bfd *, struct bfd_section *, 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) (bfd *); +. +. {* Release the memory associated with the linker hash table. *} +. void (*_bfd_link_hash_table_free) (struct bfd_link_hash_table *); +. +. {* Add symbols from this object file into the hash table. *} +. bfd_boolean (*_bfd_link_add_symbols) (bfd *, struct bfd_link_info *); +. +. {* Indicate that we are only retrieving symbol values from this section. *} +. void (*_bfd_link_just_syms) (asection *, struct bfd_link_info *); +. +. {* Do a link based on the link_order structures attached to each +. section of the BFD. *} +. bfd_boolean (*_bfd_final_link) (bfd *, struct bfd_link_info *); +. +. {* Should this section be split up into smaller pieces during linking. *} +. bfd_boolean (*_bfd_link_split_section) (bfd *, struct bfd_section *); +. +. {* Remove sections that are not referenced from the output. *} +. bfd_boolean (*_bfd_gc_sections) (bfd *, struct bfd_link_info *); +. +. {* Attempt to merge SEC_MERGE sections. *} +. bfd_boolean (*_bfd_merge_sections) (bfd *, struct bfd_link_info *); +. +. {* Is this section a member of a group? *} +. bfd_boolean (*_bfd_is_group_section) (bfd *, const struct bfd_section *); +. +. {* Discard members of a group. *} +. bfd_boolean (*_bfd_discard_group) (bfd *, struct bfd_section *); +. +. {* Check if SEC has been already linked during a reloceatable or +. final link. *} +. void (*_section_already_linked) (bfd *, struct bfd_section *); +. +. {* Routines to handle dynamic symbols and relocs. *} +.#define BFD_JUMP_TABLE_DYNAMIC(NAME) \ +. NAME##_get_dynamic_symtab_upper_bound, \ +. NAME##_canonicalize_dynamic_symtab, \ +. NAME##_get_synthetic_symtab, \ +. NAME##_get_dynamic_reloc_upper_bound, \ +. NAME##_canonicalize_dynamic_reloc +. +. {* Get the amount of memory required to hold the dynamic symbols. *} +. long (*_bfd_get_dynamic_symtab_upper_bound) (bfd *); +. {* Read in the dynamic symbols. *} +. long (*_bfd_canonicalize_dynamic_symtab) +. (bfd *, struct bfd_symbol **); +. {* Create synthetized symbols. *} +. long (*_bfd_get_synthetic_symtab) +. (bfd *, long, struct bfd_symbol **, long, struct bfd_symbol **, +. struct bfd_symbol **); +. {* Get the amount of memory required to hold the dynamic relocs. *} +. long (*_bfd_get_dynamic_reloc_upper_bound) (bfd *); +. {* Read in the dynamic relocs. *} +. long (*_bfd_canonicalize_dynamic_reloc) +. (bfd *, arelent **, struct bfd_symbol **); +. + +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. *} +. const void *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 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_bfin_vec; +extern const bfd_target bfd_elf32_bfinfdpic_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_vec; +extern const bfd_target bfd_elf32_bigarm_symbian_vec; +extern const bfd_target bfd_elf32_bigarm_vxworks_vec; +extern const bfd_target bfd_elf32_bigmips_vec; +extern const bfd_target bfd_elf32_bigmips_vxworks_vec; +extern const bfd_target bfd_elf32_cr16c_vec; +extern const bfd_target bfd_elf32_cris_vec; +extern const bfd_target bfd_elf32_crx_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_frvfdpic_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_nbsd_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_vxworks_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_vec; +extern const bfd_target bfd_elf32_littlearm_symbian_vec; +extern const bfd_target bfd_elf32_littlearm_vxworks_vec; +extern const bfd_target bfd_elf32_littlemips_vec; +extern const bfd_target bfd_elf32_littlemips_vxworks_vec; +extern const bfd_target bfd_elf32_m32c_vec; +extern const bfd_target bfd_elf32_m32r_vec; +extern const bfd_target bfd_elf32_m32rle_vec; +extern const bfd_target bfd_elf32_m32rlin_vec; +extern const bfd_target bfd_elf32_m32rlelin_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_mt_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_powerpc_vxworks_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_shl_symbian_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_sparc_vxworks_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_xc16x_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_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 m68knetbsd_vec; +extern const bfd_target m68ksysvcoff_vec; +extern const bfd_target m88kbcs_vec; +extern const bfd_target m88kmach3_vec; +extern const bfd_target m88kopenbsd_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 maxqcoff_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 z80coff_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; + +extern const bfd_target bfd_elf32_am33lin_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. */ + &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, + &bfd_elf32_bfin_vec, + &bfd_elf32_bfinfdpic_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_vec, + &bfd_elf32_bigarm_symbian_vec, + &bfd_elf32_bigarm_vxworks_vec, + &bfd_elf32_bigmips_vec, + &bfd_elf32_bigmips_vxworks_vec, + &bfd_elf32_cr16c_vec, + &bfd_elf32_cris_vec, + &bfd_elf32_crx_vec, + &bfd_elf32_d10v_vec, + &bfd_elf32_d30v_vec, + &bfd_elf32_dlx_big_vec, + &bfd_elf32_fr30_vec, + &bfd_elf32_frv_vec, + &bfd_elf32_frvfdpic_vec, + &bfd_elf32_h8300_vec, + &bfd_elf32_hppa_linux_vec, + &bfd_elf32_hppa_nbsd_vec, + &bfd_elf32_hppa_vec, + &bfd_elf32_i370_vec, + &bfd_elf32_i386_freebsd_vec, + &bfd_elf32_i386_vxworks_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 +#ifdef BFD64 + &bfd_elf32_ia64_hpux_big_vec, +#endif + &bfd_elf32_ip2k_vec, + &bfd_elf32_iq2000_vec, + &bfd_elf32_little_generic_vec, + &bfd_elf32_littlearc_vec, + &bfd_elf32_littlearm_vec, + &bfd_elf32_littlearm_symbian_vec, + &bfd_elf32_littlearm_vxworks_vec, + &bfd_elf32_littlemips_vec, + &bfd_elf32_littlemips_vxworks_vec, + &bfd_elf32_m32c_vec, + &bfd_elf32_m32r_vec, + &bfd_elf32_m32rle_vec, + &bfd_elf32_m32rlin_vec, + &bfd_elf32_m32rlelin_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_mt_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_powerpc_vxworks_vec, + &bfd_elf32_powerpcle_vec, + &bfd_elf32_s390_vec, + &bfd_elf32_sh_vec, + &bfd_elf32_shblin_vec, + &bfd_elf32_shl_vec, + &bfd_elf32_shl_symbian_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_sparc_vxworks_vec, + &bfd_elf32_tradbigmips_vec, + &bfd_elf32_tradlittlemips_vec, + &bfd_elf32_us_cris_vec, + &bfd_elf32_v850_vec, + &bfd_elf32_vax_vec, + &bfd_elf32_xc16x_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_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, + &bfd_elf64_sparc_vec, + &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 + &m68knetbsd_vec, + &m68ksysvcoff_vec, + &m88kbcs_vec, + &m88kmach3_vec, + &m88kopenbsd_vec, + &mach_o_be_vec, + &mach_o_le_vec, + &mach_o_fat_vec, + &maxqcoff_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, + &z80coff_vec, + &z8kcoff_vec, + &bfd_elf32_am33lin_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 } +}; + +/* Find a target vector, given a name or configuration triplet. */ + +static const bfd_target * +find_target (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 (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 (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 (void) +{ + 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 = 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 (int (*search_func) (const bfd_target *, void *), + 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.17/bfd/targmatch.sed b/contrib/binutils-2.17/bfd/targmatch.sed new file mode 100644 index 0000000000..2716876547 --- /dev/null +++ b/contrib/binutils-2.17/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.17/bfd/tekhex.c b/contrib/binutils-2.17/bfd/tekhex.c new file mode 100644 index 0000000000..afe42cc948 --- /dev/null +++ b/contrib/binutils-2.17/bfd/tekhex.c @@ -0,0 +1,1004 @@ +/* BFD backend for Extended Tektronix Hex Format objects. + Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, + 2003, 2004 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 described 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 ISHEX(x) hex_p(x) +#define TOHEX(d, x) \ + (d)[1] = digs[(x) & 0xf]; \ + (d)[0] = digs[((x)>>4)&0xf]; + +/* 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 (void) +{ + 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_boolean +getvalue (char **srcp, bfd_vma *valuep) +{ + char *src = *srcp; + bfd_vma value = 0; + unsigned int len; + + if (!ISHEX (*src)) + return FALSE; + + len = hex_value (*src++); + if (len == 0) + len = 16; + while (len--) + { + if (!ISHEX (*src)) + return FALSE; + value = value << 4 | hex_value (*src++); + } + + *srcp = src; + *valuep = value; + return TRUE; +} + +static bfd_boolean +getsym (char *dstp, char **srcp, unsigned int *lenp) +{ + char *src = *srcp; + unsigned int i; + unsigned int len; + + if (!ISHEX (*src)) + return FALSE; + + 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; + *lenp = len; + return TRUE; +} + +static struct data_struct * +find_chunk (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 = 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 (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 bfd_boolean +first_phase (bfd *abfd, int type, char *src) +{ + asection *section = bfd_abs_section_ptr; + unsigned int len; + bfd_vma val; + char sym[17]; /* A symbol can only be 16chars long. */ + + switch (type) + { + case '6': + /* Data record - read it and store it. */ + { + bfd_vma addr; + + if (!getvalue (&src, &addr)) + return FALSE; + + while (*src) + { + insert_byte (abfd, HEX (src), addr); + src += 2; + addr++; + } + } + + return TRUE; + case '3': + /* Symbol record, read the segment. */ + if (!getsym (sym, &src, &len)) + return FALSE; + section = bfd_get_section_by_name (abfd, sym); + if (section == NULL) + { + char *n = bfd_alloc (abfd, (bfd_size_type) len + 1); + + if (!n) + return FALSE; + memcpy (n, sym, len + 1); + section = bfd_make_section (abfd, n); + } + while (*src) + { + switch (*src) + { + case '1': /* Section range. */ + src++; + if (!getvalue (&src, §ion->vma)) + return FALSE; + if (!getvalue (&src, &val)) + return FALSE; + section->size = val - 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 = bfd_alloc (abfd, amt); + char stype = (*src); + + if (!new) + return FALSE; + 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; + if (!getsym (sym, &src, &len)) + return FALSE; + new->symbol.name = bfd_alloc (abfd, (bfd_size_type) len + 1); + if (!new->symbol.name) + return FALSE; + 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; + if (!getvalue (&src, &val)) + return FALSE; + new->symbol.value = val - section->vma; + } + default: + return FALSE; + } + } + } + + return TRUE; +} + +/* Pass over a tekhex, calling one of the above functions on each + record. */ + +static bfd_boolean +pass_over (bfd *abfd, bfd_boolean (*func) (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; + + /* Already read five char. */ + chars_on_line = HEX (src) - 5; + + if (bfd_bread (src, (bfd_size_type) chars_on_line, abfd) != chars_on_line) + abort (); /* FIXME. */ + + /* Put a null at the end. */ + src[chars_on_line] = 0; + + if (!func (abfd, type, src)) + return FALSE; + } + + return TRUE; +} + +static long +tekhex_canonicalize_symtab (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 (bfd *abfd) +{ + return (abfd->symcount + 1) * (sizeof (struct tekhex_asymbol_struct *)); + +} + +static bfd_boolean +tekhex_mkobject (bfd *abfd) +{ + tdata_type *tdata; + + tdata = bfd_alloc (abfd, (bfd_size_type) sizeof (tdata_type)); + if (!tdata) + return FALSE; + abfd->tdata.tekhex_data = tdata; + tdata->type = 1; + tdata->head = NULL; + tdata->symbols = NULL; + tdata->data = 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 (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 NULL; + + tekhex_mkobject (abfd); + + if (!pass_over (abfd, first_phase)) + return NULL; + + return abfd->xvec; +} + +static void +move_section_contents (bfd *abfd, + asection *section, + const void * 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 = 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 (bfd *abfd, + asection *section, + void * 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; + } + + return FALSE; +} + +static bfd_boolean +tekhex_set_arch_mach (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 (bfd *abfd, + sec_ptr section, + const void * 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->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; + } + + return FALSE; +} + +static void +writevalue (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 (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 (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 (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 != 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 != NULL; s = s->next) + { + char *dst = buffer; + + writesym (&dst, s->name); + *dst++ = '1'; + writevalue (&dst, s->vma); + writevalue (&dst, s->vma + s->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 (bfd *abfd ATTRIBUTE_UNUSED, + bfd_boolean exec ATTRIBUTE_UNUSED) +{ + return 0; +} + +static asymbol * +tekhex_make_empty_symbol (bfd *abfd) +{ + bfd_size_type amt = sizeof (struct tekhex_symbol_struct); + tekhex_symbol_type *new = bfd_zalloc (abfd, amt); + + if (!new) + return NULL; + new->symbol.the_bfd = abfd; + new->prev = NULL; + return &(new->symbol); +} + +static void +tekhex_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED, + asymbol *symbol, + symbol_info *ret) +{ + bfd_symbol_info (symbol, ret); +} + +static void +tekhex_print_symbol (bfd *abfd, + void * 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, (void *) 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_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) +#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_find_inliner_info _bfd_nosymbols_find_inliner_info +#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_is_group_section bfd_generic_is_group_section +#define tekhex_bfd_discard_group bfd_generic_discard_group +#define tekhex_section_already_linked _bfd_generic_section_already_linked +#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, /* Headers. */ + + { + _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, + + NULL +}; diff --git a/contrib/binutils-2.17/bfd/version.h b/contrib/binutils-2.17/bfd/version.h new file mode 100644 index 0000000000..2ddbca90bd --- /dev/null +++ b/contrib/binutils-2.17/bfd/version.h @@ -0,0 +1,3 @@ +#define BFD_VERSION_DATE 20060623 +#define BFD_VERSION @bfd_version@ +#define BFD_VERSION_STRING @bfd_version_string@ diff --git a/contrib/binutils-2.17/binutils/addr2line.c b/contrib/binutils-2.17/binutils/addr2line.c new file mode 100644 index 0000000000..7cd67bc0a1 --- /dev/null +++ b/contrib/binutils-2.17/binutils/addr2line.c @@ -0,0 +1,407 @@ +/* addr2line.c -- convert addresses to line number and function name + Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006 + 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, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 "config.h" +#include + +#include "bfd.h" +#include "getopt.h" +#include "libiberty.h" +#include "demangle.h" +#include "bucomm.h" +#include "budemang.h" + +static bfd_boolean unwind_inlines; /* -i, unwind inlined functions. */ +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'}, + {"inlines", no_argument, NULL, 'i'}, + {"section", required_argument, NULL, 'j'}, + {"target", required_argument, NULL, 'b'}, + {"help", no_argument, NULL, 'H'}, + {"version", no_argument, NULL, 'V'}, + {0, no_argument, 0, 0} +}; + +static void usage (FILE *, int); +static void slurp_symtab (bfd *); +static void find_address_in_section (bfd *, asection *, void *); +static void find_offset_in_section (bfd *, asection *); +static void translate_addresses (bfd *, asection *); +static void process_file (const char *, const char *, const char *); + +/* Print a usage message to STREAM and exit with STATUS. */ + +static void +usage (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\ + @ Read options from \n\ + -b --target= Set the binary file format\n\ + -e --exe= Set the input file name (default is a.out)\n\ + -i --inlines Unwind inlined functions\n\ + -j --section= Read section-relative offsets instead of addresses\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 (bfd *abfd) +{ + long symcount; + unsigned int size; + + if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0) + return; + + symcount = bfd_read_minisymbols (abfd, FALSE, (void *) &syms, &size); + if (symcount == 0) + symcount = bfd_read_minisymbols (abfd, TRUE /* dynamic */, (void *) &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 (bfd *abfd, asection *section, + void *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 (section); + if (pc >= vma + size) + return; + + found = bfd_find_nearest_line (abfd, section, syms, pc - vma, + &filename, &functionname, &line); +} + +/* Look for an offset in a section. This is directly called. */ + +static void +find_offset_in_section (bfd *abfd, asection *section) +{ + bfd_size_type size; + + if (found) + return; + + if ((bfd_get_section_flags (abfd, section) & SEC_ALLOC) == 0) + return; + + size = bfd_get_section_size (section); + if (pc >= size) + return; + + found = bfd_find_nearest_line (abfd, section, syms, pc, + &filename, &functionname, &line); +} + +/* Read hexadecimal addresses from stdin, translate into + file_name:line_number and optionally function name. */ + +static void +translate_addresses (bfd *abfd, asection *section) +{ + 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; + if (section) + find_offset_in_section (abfd, section); + else + bfd_map_over_sections (abfd, find_address_in_section, NULL); + + if (! found) + { + if (with_functions) + printf ("??\n"); + printf ("??:0\n"); + } + else + { + do { + 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); + if (!unwind_inlines) + found = FALSE; + else + found = bfd_find_inliner_info (abfd, &filename, &functionname, &line); + } while (found); + + } + + /* 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 (const char *file_name, const char *section_name, + const char *target) +{ + bfd *abfd; + asection *section; + char **matching; + + if (get_file_size (file_name) < 1) + return; + + abfd = bfd_openr (file_name, target); + if (abfd == NULL) + bfd_fatal (file_name); + + if (bfd_check_format (abfd, bfd_archive)) + fatal (_("%s: cannot 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); + } + + if (section_name != NULL) + { + section = bfd_get_section_by_name (abfd, section_name); + if (section == NULL) + fatal (_("%s: cannot find section %s"), file_name, section_name); + } + else + section = NULL; + + slurp_symtab (abfd); + + translate_addresses (abfd, section); + + if (syms != NULL) + { + free (syms); + syms = NULL; + } + + bfd_close (abfd); +} + +int +main (int argc, char **argv) +{ + const char *file_name; + const char *section_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); + + expandargv (&argc, &argv); + + bfd_init (); + set_default_bfd_target (); + + file_name = NULL; + section_name = NULL; + target = NULL; + while ((c = getopt_long (argc, argv, "b:Ce:sfHhij:Vv", 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; + case 'i': + unwind_inlines = TRUE; + break; + case 'j': + section_name = optarg; + break; + default: + usage (stderr, 1); + break; + } + } + + if (file_name == NULL) + file_name = "a.out"; + + addr = argv + optind; + naddr = argc - optind; + + process_file (file_name, section_name, target); + + return 0; +} diff --git a/contrib/binutils-2.17/binutils/ar.c b/contrib/binutils-2.17/binutils/ar.c new file mode 100644 index 0000000000..fe1c640222 --- /dev/null +++ b/contrib/binutils-2.17/binutils/ar.c @@ -0,0 +1,1263 @@ +/* ar.c - Archive modify and extract. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 consistent. */ + +#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 + +/* Kludge declaration from BFD! This is ugly! FIXME! XXX */ + +struct ar_hdr * + bfd_special_undocumented_glue (bfd * abfd, const char *filename); + +/* Static declarations */ + +static void mri_emul (void); +static const char *normalize (const char *, bfd *); +static void remove_output (void); +static void map_over_members (bfd *, void (*)(bfd *), char **, int); +static void print_contents (bfd * member); +static void delete_members (bfd *, char **files_to_delete); + +static void move_members (bfd *, char **files_to_move); +static void replace_members + (bfd *, char **files_to_replace, bfd_boolean quick); +static void print_descr (bfd * abfd); +static void write_archive (bfd *); +static void ranlib_only (const char *archname); +static void ranlib_touch (const char *archname); +static void usage (int); + +/** Globals and flags */ + +static 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 explicitly 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 (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 (void) +{ + 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 (bfd *arch, void (*function)(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 (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 [ - read options from \n")); + + ar_emul_usage (s); + } + else + { + /* xgettext:c-format */ + fprintf (s, _("Usage: %s [options] archive\n"), program_name); + fprintf (s, _(" Generate an index to speed access to archives\n")); + fprintf (s, _(" The options are:\n\ + @ Read options from \n\ + -h --help Print this help message\n\ + -V --version Print version information\n")); + } + + list_supported_targets (program_name, stderr); + + if (help) + fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO); + + xexit (help ? 0 : 1); +} + +/* Normalize a file name specified on the command line into a file + name which we will use in an archive. */ + +static const char * +normalize (const char *file, bfd *abfd) +{ + const char *filename; + + if (full_pathname) + return file; + + 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; + + 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 (void) +{ + if (output_filename != NULL) + { + if (output_bfd != NULL) + bfd_cache_close (output_bfd); + if (output_file != NULL) + fclose (output_file); + unlink_if_ordinary (output_filename); + } +} + +/* The option parsing should be in its own function. + It will be when I have getopt working. */ + +int main (int, char **); + +int +main (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; + int do_posix = 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); + + program_name = argv[0]; + xmalloc_set_program_name (program_name); + + expandargv (&argc, &argv); + + 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_index = 1; + arg_ptr = argv[arg_index]; + + if (*arg_ptr == '-') + { + /* When the first option starts with '-' we support POSIX-compatible + option parsing. */ + do_posix = 1; + ++arg_ptr; /* compatibility */ + } + + do + { + 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); + } + } + + /* With POSIX-compatible option parsing continue with the next + argument if it starts with '-'. */ + if (do_posix && arg_index + 1 < argc && argv[arg_index + 1][0] == '-') + arg_ptr = argv[++arg_index] + 1; + else + do_posix = 0; + } + while (do_posix); + + if (show_version) + print_version ("ar"); + + ++arg_index; + if (arg_index >= argc) + usage (0); + + if (mri_mode) + { + mri_emul (); + } + else + { + bfd *arch; + + /* 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 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[arg_index]); + xexit (0); + } + + if (operation == none) + fatal (_("no operation specified")); + + if (newer_only && operation != replace) + fatal (_("`u' is only meaningful with the `r' option.")); + + 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; + + 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 (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); + else if (!silent_create) + non_fatal (_("creating %s"), 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 (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<%s>\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 (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 access time to modification time. Only st_mtime is + initialized by bfd_stat_arch_elt. */ + buf.st_atime = buf.st_mtime; + set_times (bfd_get_filename (abfd), &buf); + } + + free (cbuf); +} + +static void +write_archive (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 (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 (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 (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 (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 (const char *archname) +{ + bfd *arch; + + if (get_file_size (archname) < 1) + return; + 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 (const char *archname) +{ +#ifdef __GO32__ + /* I don't think updating works on go32. */ + ranlib_only (archname); +#else + int f; + bfd *arch; + char **matching; + + if (get_file_size (archname) < 1) + return; + 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 (bfd *abfd) +{ + print_arelt_descr (stdout, abfd, verbose); +} diff --git a/contrib/binutils-2.17/binutils/arlex.c b/contrib/binutils-2.17/binutils/arlex.c new file mode 100644 index 0000000000..cd9bd52d08 --- /dev/null +++ b/contrib/binutils-2.17/binutils/arlex.c @@ -0,0 +1,1856 @@ +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header: /cvs/src/src/binutils/Attic/arlex.c,v 1.1.16.1 2006/04/16 18:36:40 drow Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include +#include + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include +#ifndef _WIN32 +#include +#endif + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include +#include +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart YY_PROTO(( FILE *input_file )); + +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 40 +#define YY_END_OF_BUFFER 41 +static yyconst short int yy_accept[177] = + { 0, + 0, 0, 41, 40, 39, 38, 35, 32, 33, 36, + 40, 34, 37, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 36, 31, 37, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 7, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 22, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + + 35, 35, 35, 10, 11, 12, 35, 15, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 25, 26, 27, + 35, 30, 35, 35, 35, 3, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 18, 35, 35, 35, 35, + 35, 35, 35, 1, 2, 4, 5, 35, 35, 35, + 35, 35, 16, 17, 19, 20, 35, 35, 35, 35, + 35, 35, 8, 9, 13, 14, 35, 23, 24, 28, + 29, 35, 35, 6, 21, 0 + } ; + +static yyconst int yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 1, 1, 1, 4, 1, 1, 1, 5, + 6, 7, 8, 9, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 10, 1, + 1, 1, 1, 1, 11, 12, 13, 14, 15, 16, + 4, 17, 18, 4, 4, 19, 20, 21, 22, 23, + 4, 24, 25, 26, 27, 28, 4, 29, 30, 4, + 1, 4, 1, 1, 4, 1, 31, 32, 33, 34, + + 35, 36, 4, 37, 38, 4, 4, 39, 40, 41, + 42, 43, 4, 44, 45, 46, 47, 48, 4, 49, + 50, 4, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst int yy_meta[51] = + { 0, + 1, 2, 1, 3, 1, 1, 1, 1, 1, 1, + 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 + } ; + +static yyconst short int yy_base[180] = + { 0, + 0, 0, 193, 194, 194, 194, 0, 194, 194, 0, + 190, 194, 0, 177, 32, 37, 32, 163, 174, 170, + 164, 171, 174, 169, 149, 15, 22, 17, 135, 146, + 142, 136, 143, 146, 141, 0, 0, 194, 0, 161, + 159, 158, 153, 147, 156, 143, 149, 148, 141, 150, + 141, 135, 138, 127, 125, 124, 119, 113, 122, 109, + 115, 114, 107, 116, 107, 101, 104, 43, 136, 135, + 130, 129, 0, 119, 123, 118, 114, 118, 119, 122, + 124, 25, 104, 103, 98, 97, 0, 87, 91, 86, + 82, 86, 87, 90, 92, 105, 100, 97, 94, 93, + + 105, 106, 102, 0, 0, 0, 104, 0, 92, 75, + 70, 67, 64, 63, 75, 76, 72, 0, 0, 0, + 74, 0, 62, 91, 88, 0, 86, 85, 73, 85, + 79, 83, 70, 62, 59, 0, 57, 56, 44, 56, + 50, 54, 41, 0, 0, 0, 0, 63, 58, 59, + 67, 66, 0, 0, 0, 0, 38, 33, 34, 42, + 41, 51, 0, 0, 0, 0, 30, 0, 0, 0, + 0, 43, 21, 0, 0, 194, 65, 66, 69 + } ; + +static yyconst short int yy_def[180] = + { 0, + 176, 1, 176, 176, 176, 176, 177, 176, 176, 178, + 176, 176, 179, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 178, 176, 179, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 0, 176, 176, 176 + } ; + +static yyconst short int yy_nxt[245] = + { 0, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 7, 15, 16, 17, 18, 19, 7, 20, 7, + 7, 21, 7, 22, 23, 7, 7, 24, 7, 7, + 25, 7, 26, 27, 28, 29, 30, 7, 31, 7, + 7, 32, 7, 33, 34, 7, 7, 35, 7, 7, + 41, 43, 45, 55, 44, 42, 57, 59, 56, 58, + 46, 96, 97, 110, 111, 60, 37, 36, 37, 39, + 175, 39, 174, 173, 172, 171, 170, 169, 168, 167, + 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, + 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, + + 146, 145, 144, 143, 142, 141, 140, 139, 138, 137, + 136, 135, 134, 133, 132, 131, 130, 129, 128, 127, + 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, + 116, 115, 114, 113, 112, 109, 108, 107, 106, 105, + 104, 103, 102, 101, 100, 99, 98, 95, 94, 93, + 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, + 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, + 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, + 62, 61, 54, 53, 52, 51, 50, 49, 48, 47, + 40, 38, 176, 3, 176, 176, 176, 176, 176, 176, + + 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, + 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, + 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, + 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, + 176, 176, 176, 176 + } ; + +static yyconst short int yy_chk[245] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 15, 16, 17, 26, 16, 15, 27, 28, 26, 27, + 17, 68, 68, 82, 82, 28, 178, 177, 178, 179, + 173, 179, 172, 167, 162, 161, 160, 159, 158, 157, + 152, 151, 150, 149, 148, 143, 142, 141, 140, 139, + 138, 137, 135, 134, 133, 132, 131, 130, 129, 128, + + 127, 125, 124, 123, 121, 117, 116, 115, 114, 113, + 112, 111, 110, 109, 107, 103, 102, 101, 100, 99, + 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, + 88, 86, 85, 84, 83, 81, 80, 79, 78, 77, + 76, 75, 74, 72, 71, 70, 69, 67, 66, 65, + 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, + 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, + 44, 43, 42, 41, 40, 35, 34, 33, 32, 31, + 30, 29, 25, 24, 23, 22, 21, 20, 19, 18, + 14, 11, 3, 176, 176, 176, 176, 176, 176, 176, + + 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, + 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, + 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, + 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, + 176, 176, 176, 176 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "arlex.l" +#define INITIAL 0 +#line 2 "arlex.l" +/* arlex.l - Strange script language lexer */ + +/* Copyright 1992, 1997, 2000, 2001, 2002, 2003, 2004 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + + +/* Contributed by Steve Chamberlain . */ + +#define DONTDECLARE_MALLOC +#include "ansidecl.h" +#include "libiberty.h" +#include "arparse.h" + +#define YY_NO_UNPUT + +extern int yylex (void); + +int linenumber; +#line 511 "arlex.c" + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + } +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 41 "arlex.l" + + +#line 676 "arlex.c" + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 177 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 194 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 43 "arlex.l" +{ return ADDLIB; } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 44 "arlex.l" +{ return ADDMOD; } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 45 "arlex.l" +{ return CLEAR; } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 46 "arlex.l" +{ return CREATE; } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 47 "arlex.l" +{ return DELETE; } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 48 "arlex.l" +{ return DIRECTORY; } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 49 "arlex.l" +{ return END; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 50 "arlex.l" +{ return EXTRACT; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 51 "arlex.l" +{ return FULLDIR; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 52 "arlex.l" +{ return HELP; } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 53 "arlex.l" +{ return LIST; } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 54 "arlex.l" +{ return OPEN; } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 55 "arlex.l" +{ return REPLACE; } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 56 "arlex.l" +{ return VERBOSE; } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 57 "arlex.l" +{ return SAVE; } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 58 "arlex.l" +{ return ADDLIB; } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 59 "arlex.l" +{ return ADDMOD; } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 60 "arlex.l" +{ return CLEAR; } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 61 "arlex.l" +{ return CREATE; } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 62 "arlex.l" +{ return DELETE; } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 63 "arlex.l" +{ return DIRECTORY; } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 64 "arlex.l" +{ return END; } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 65 "arlex.l" +{ return EXTRACT; } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 66 "arlex.l" +{ return FULLDIR; } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 67 "arlex.l" +{ return HELP; } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 68 "arlex.l" +{ return LIST; } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 69 "arlex.l" +{ return OPEN; } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 70 "arlex.l" +{ return REPLACE; } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 71 "arlex.l" +{ return VERBOSE; } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 72 "arlex.l" +{ return SAVE; } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 73 "arlex.l" +{ linenumber ++; } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 74 "arlex.l" +{ return '('; } + YY_BREAK +case 33: +YY_RULE_SETUP +#line 75 "arlex.l" +{ return ')'; } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 76 "arlex.l" +{ return ','; } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 77 "arlex.l" +{ + yylval.name = xstrdup (yytext); + return FILENAME; + } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 81 "arlex.l" +{ } + YY_BREAK +case 37: +YY_RULE_SETUP +#line 82 "arlex.l" +{ } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 83 "arlex.l" +{ } + YY_BREAK +case 39: +YY_RULE_SETUP +#line 84 "arlex.l" +{ linenumber ++; return NEWLINE; } + YY_BREAK +case 40: +YY_RULE_SETUP +#line 86 "arlex.l" +ECHO; + YY_BREAK +#line 962 "arlex.c" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = + yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + { + register char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 177 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + register int yy_is_jam; + register char *yy_cp = yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 177 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 176); + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + { + int c; + + *yy_c_buf_p = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* This was really a NUL. */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + yy_hold_char = *++yy_c_buf_p; + + + return c; + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + +#ifndef _WIN32 +#include +#else +#ifndef YY_ALWAYS_INTERACTIVE +#ifndef YY_NEVER_INTERACTIVE +extern int isatty YY_PROTO(( int )); +#endif +#endif +#endif + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 86 "arlex.l" + +#ifndef yywrap +/* Needed for lex, though not flex. */ +int yywrap(void) { return 1; } +#endif diff --git a/contrib/binutils-2.17/binutils/arparse.c b/contrib/binutils-2.17/binutils/arparse.c new file mode 100644 index 0000000000..21fa13a44b --- /dev/null +++ b/contrib/binutils-2.17/binutils/arparse.c @@ -0,0 +1,1605 @@ +/* A Bison parser, made by GNU Bison 2.1. */ + +/* Skeleton parser for Yacc-like parsing with Bison, + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* Written by Richard Stallman by simplifying the original so called + ``semantic'' parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.1" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + NEWLINE = 258, + VERBOSE = 259, + FILENAME = 260, + ADDLIB = 261, + LIST = 262, + ADDMOD = 263, + CLEAR = 264, + CREATE = 265, + DELETE = 266, + DIRECTORY = 267, + END = 268, + EXTRACT = 269, + FULLDIR = 270, + HELP = 271, + QUIT = 272, + REPLACE = 273, + SAVE = 274, + OPEN = 275 + }; +#endif +/* Tokens. */ +#define NEWLINE 258 +#define VERBOSE 259 +#define FILENAME 260 +#define ADDLIB 261 +#define LIST 262 +#define ADDMOD 263 +#define CLEAR 264 +#define CREATE 265 +#define DELETE 266 +#define DIRECTORY 267 +#define END 268 +#define EXTRACT 269 +#define FULLDIR 270 +#define HELP 271 +#define QUIT 272 +#define REPLACE 273 +#define SAVE 274 +#define OPEN 275 + + + + +/* Copy the first part of user declarations. */ +#line 1 "arparse.y" + +/* arparse.y - Stange script language parser */ + +/* Copyright 1992, 1993, 1995, 1997, 1999, 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 (void); +static int yyerror (const char *); + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + +#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) +#line 37 "arparse.y" +typedef union YYSTYPE { + char *name; +struct list *list ; + +} YYSTYPE; +/* Line 196 of yacc.c. */ +#line 167 "arparse.c" +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Line 219 of yacc.c. */ +#line 179 "arparse.c" + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) && (defined (__STDC__) || defined (__cplusplus)) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +#if ! defined (yyoverflow) || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# else +# define YYSTACK_ALLOC alloca +# if defined (__STDC__) || defined (__cplusplus) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYINCLUDED_STDLIB_H +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2005 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM ((YYSIZE_T) -1) +# endif +# ifdef __cplusplus +extern "C" { +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if (! defined (malloc) && ! defined (YYINCLUDED_STDLIB_H) \ + && (defined (__STDC__) || defined (__cplusplus))) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if (! defined (free) && ! defined (YYINCLUDED_STDLIB_H) \ + && (defined (__STDC__) || defined (__cplusplus))) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifdef __cplusplus +} +# endif +# endif +#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */ + + +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short int yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short int) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined (__GNUC__) && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined (__STDC__) || defined (__cplusplus) + typedef signed char yysigned_char; +#else + typedef short int yysigned_char; +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 3 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 34 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 24 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 22 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 42 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 53 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 275 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const unsigned char yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 21, 22, 2, 2, 23, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const unsigned char yyprhs[] = +{ + 0, 0, 3, 4, 7, 10, 11, 14, 16, 18, + 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, + 40, 42, 44, 45, 48, 51, 53, 56, 59, 61, + 63, 66, 69, 73, 78, 80, 81, 85, 86, 90, + 91, 93, 94 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yysigned_char yyrhs[] = +{ + 25, 0, -1, -1, 26, 27, -1, 27, 28, -1, + -1, 29, 3, -1, 37, -1, 38, -1, 45, -1, + 40, -1, 39, -1, 32, -1, 34, -1, 36, -1, + 30, -1, 31, -1, 33, -1, 35, -1, 13, -1, + 1, -1, 5, -1, -1, 14, 43, -1, 18, 43, + -1, 9, -1, 11, 43, -1, 8, 43, -1, 7, + -1, 19, -1, 20, 5, -1, 10, 5, -1, 6, + 5, 42, -1, 12, 5, 42, 41, -1, 5, -1, + -1, 21, 43, 22, -1, -1, 43, 44, 5, -1, + -1, 23, -1, -1, 4, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const unsigned char yyrline[] = +{ + 0, 68, 68, 68, 72, 73, 77, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 101, 106, 111, 116, 120, 125, 130, + 137, 142, 148, 152, 159, 161, 165, 168, 172, 178, + 183, 184, 189 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "NEWLINE", "VERBOSE", "FILENAME", + "ADDLIB", "LIST", "ADDMOD", "CLEAR", "CREATE", "DELETE", "DIRECTORY", + "END", "EXTRACT", "FULLDIR", "HELP", "QUIT", "REPLACE", "SAVE", "OPEN", + "'('", "')'", "','", "$accept", "start", "@1", "session", "command_line", + "command", "extract_command", "replace_command", "clear_command", + "delete_command", "addmod_command", "list_command", "save_command", + "open_command", "create_command", "addlib_command", "directory_command", + "optional_filename", "modulelist", "modulename", "optcomma", + "verbose_command", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const unsigned short int yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 40, 41, 44 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const unsigned char yyr1[] = +{ + 0, 24, 26, 25, 27, 27, 28, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 41, 42, 42, 43, 43, + 44, 44, 45 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const unsigned char yyr2[] = +{ + 0, 2, 0, 2, 2, 0, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 2, 2, 1, 2, 2, 1, 1, + 2, 2, 3, 4, 1, 0, 3, 0, 3, 0, + 1, 0, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const unsigned char yydefact[] = +{ + 2, 0, 5, 1, 0, 20, 42, 21, 0, 28, + 39, 25, 0, 39, 0, 19, 39, 39, 29, 0, + 4, 0, 15, 16, 12, 17, 13, 18, 14, 7, + 8, 11, 10, 9, 37, 27, 31, 26, 37, 23, + 24, 30, 6, 39, 32, 40, 0, 35, 41, 38, + 34, 33, 36 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yysigned_char yydefgoto[] = +{ + -1, 1, 2, 4, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 51, 44, 35, + 46, 33 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -14 +static const yysigned_char yypact[] = +{ + -14, 1, -14, -14, 5, -14, -14, -14, 2, -14, + -14, -14, 21, -14, 22, -14, -14, -14, -14, 23, + -14, 26, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, 10, -3, -14, -3, 10, -3, + -3, -14, -14, -14, -14, -14, 27, 28, -1, -14, + -14, -14, -14 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yysigned_char yypgoto[] = +{ + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -4, -13, + -14, -14 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -42 +static const yysigned_char yytable[] = +{ + 37, 3, -41, 39, 40, -3, 5, 34, -22, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 45, 52, 45, 17, 18, 19, 36, 38, 41, 42, + 48, 43, 49, 50, 47 +}; + +static const unsigned char yycheck[] = +{ + 13, 0, 5, 16, 17, 0, 1, 5, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 23, 22, 23, 18, 19, 20, 5, 5, 5, 3, + 43, 21, 5, 5, 38 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const unsigned char yystos[] = +{ + 0, 25, 26, 0, 27, 1, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 18, 19, 20, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 45, 5, 43, 5, 43, 5, 43, + 43, 5, 3, 21, 42, 23, 44, 42, 43, 5, + 5, 41, 22 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (0) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (N) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (0) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yysymprint (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_stack_print (short int *bottom, short int *top) +#else +static void +yy_stack_print (bottom, top) + short int *bottom; + short int *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (/* Nothing. */; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_reduce_print (int yyrule) +#else +static void +yy_reduce_print (yyrule) + int yyrule; +#endif +{ + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu), ", + yyrule - 1, yylno); + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) + YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); + YYFPRINTF (stderr, "-> %s\n", yytname[yyr1[yyrule]]); +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (Rule); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif +{ + const char *yys = yystr; + + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; +} +# endif +# endif + +# ifndef yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + size_t yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +#endif /* YYERROR_VERBOSE */ + + + +#if YYDEBUG +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep) +#else +static void +yysymprint (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + switch (yytype) + { + default: + break; + } + YYFPRINTF (yyoutput, ")"); +} + +#endif /* ! YYDEBUG */ +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM); +# else +int yyparse (); +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + +/* The look-ahead symbol. */ +int yychar; + +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM) +# else +int yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int +yyparse (void) +#else +int +yyparse () + ; +#endif +#endif +{ + + int yystate; + int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short int yyssa[YYINITDEPTH]; + short int *yyss = yyssa; + short int *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + + +#define YYPOPSTACK (yyvsp--, yyssp--) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + short int *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + short int *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a look-ahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to look-ahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a look-ahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the look-ahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; + + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + yystate = yyn; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 68 "arparse.y" + { prompt(); } + break; + + case 6: +#line 77 "arparse.y" + { prompt(); } + break; + + case 19: +#line 93 "arparse.y" + { ar_end(); return 0; } + break; + + case 21: +#line 95 "arparse.y" + { yyerror("foo"); } + break; + + case 23: +#line 102 "arparse.y" + { ar_extract((yyvsp[0].list)); } + break; + + case 24: +#line 107 "arparse.y" + { ar_replace((yyvsp[0].list)); } + break; + + case 25: +#line 112 "arparse.y" + { ar_clear(); } + break; + + case 26: +#line 117 "arparse.y" + { ar_delete((yyvsp[0].list)); } + break; + + case 27: +#line 121 "arparse.y" + { ar_addmod((yyvsp[0].list)); } + break; + + case 28: +#line 126 "arparse.y" + { ar_list(); } + break; + + case 29: +#line 131 "arparse.y" + { ar_save(); } + break; + + case 30: +#line 138 "arparse.y" + { ar_open((yyvsp[0].name),0); } + break; + + case 31: +#line 143 "arparse.y" + { ar_open((yyvsp[0].name),1); } + break; + + case 32: +#line 149 "arparse.y" + { ar_addlib((yyvsp[-1].name),(yyvsp[0].list)); } + break; + + case 33: +#line 153 "arparse.y" + { ar_directory((yyvsp[-2].name), (yyvsp[-1].list), (yyvsp[0].name)); } + break; + + case 34: +#line 160 "arparse.y" + { (yyval.name) = (yyvsp[0].name); } + break; + + case 35: +#line 161 "arparse.y" + { (yyval.name) = 0; } + break; + + case 36: +#line 166 "arparse.y" + { (yyval.list) = (yyvsp[-1].list); } + break; + + case 37: +#line 168 "arparse.y" + { (yyval.list) = 0; } + break; + + case 38: +#line 173 "arparse.y" + { struct list *n = (struct list *) malloc(sizeof(struct list)); + n->next = (yyvsp[-2].list); + n->name = (yyvsp[0].name); + (yyval.list) = n; + } + break; + + case 39: +#line 178 "arparse.y" + { (yyval.list) = 0; } + break; + + case 42: +#line 190 "arparse.y" + { verbose = !verbose; } + break; + + + default: break; + } + +/* Line 1126 of yacc.c. */ +#line 1327 "arparse.c" + + yyvsp -= yylen; + yyssp -= yylen; + + + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (YYPACT_NINF < yyn && yyn < YYLAST) + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + char *yymsg = 0; +# define YYERROR_VERBOSE_ARGS_MAXIMUM 5 + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +#if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +#endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= yysize1 < yysize; + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= yysize1 < yysize; + yysize = yysize1; + + if (!yysize_overflow && yysize <= YYSTACK_ALLOC_MAXIMUM) + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yymsg; + int yyi = 0; + while ((*yyp = *yyf)) + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + yyerror (yymsg); + YYSTACK_FREE (yymsg); + } + else + { + yyerror (YY_("syntax error")); + goto yyexhaustedlab; + } + } + else +#endif /* YYERROR_VERBOSE */ + yyerror (YY_("syntax error")); + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse look-ahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse look-ahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (0) + goto yyerrorlab; + +yyvsp -= yylen; + yyssp -= yylen; + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", yystos[yystate], yyvsp); + YYPOPSTACK; + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK; + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; +} + + +#line 194 "arparse.y" + + +static int +yyerror (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.17/binutils/arparse.h b/contrib/binutils-2.17/binutils/arparse.h new file mode 100644 index 0000000000..41044396e1 --- /dev/null +++ b/contrib/binutils-2.17/binutils/arparse.h @@ -0,0 +1,92 @@ +/* A Bison parser, made by GNU Bison 2.1. */ + +/* Skeleton parser for Yacc-like parsing with Bison, + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + NEWLINE = 258, + VERBOSE = 259, + FILENAME = 260, + ADDLIB = 261, + LIST = 262, + ADDMOD = 263, + CLEAR = 264, + CREATE = 265, + DELETE = 266, + DIRECTORY = 267, + END = 268, + EXTRACT = 269, + FULLDIR = 270, + HELP = 271, + QUIT = 272, + REPLACE = 273, + SAVE = 274, + OPEN = 275 + }; +#endif +/* Tokens. */ +#define NEWLINE 258 +#define VERBOSE 259 +#define FILENAME 260 +#define ADDLIB 261 +#define LIST 262 +#define ADDMOD 263 +#define CLEAR 264 +#define CREATE 265 +#define DELETE 266 +#define DIRECTORY 267 +#define END 268 +#define EXTRACT 269 +#define FULLDIR 270 +#define HELP 271 +#define QUIT 272 +#define REPLACE 273 +#define SAVE 274 +#define OPEN 275 + + + + +#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) +#line 37 "arparse.y" +typedef union YYSTYPE { + char *name; +struct list *list ; + +} YYSTYPE; +/* Line 1447 of yacc.c. */ +#line 84 "arparse.h" +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + +extern YYSTYPE yylval; + + + diff --git a/contrib/binutils-2.17/binutils/arsup.c b/contrib/binutils-2.17/binutils/arsup.c new file mode 100644 index 0000000000..189490b307 --- /dev/null +++ b/contrib/binutils-2.17/binutils/arsup.c @@ -0,0 +1,478 @@ +/* arsup.c - Archive support for MRI compatibility + Copyright 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003, + 2004 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 + (bfd *, void (*function) (bfd *, bfd *), struct list *); +static void ar_directory_doer (bfd *, bfd *); +static void ar_addlib_doer (bfd *, bfd *); + +extern int verbose; + +static bfd *obfd; +static char *real_name; +static FILE *outfile; + +static void +map_over_list (bfd *arch, void (*function) (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); + } + } +} + + + +static void +ar_directory_doer (bfd *abfd, bfd *ignore ATTRIBUTE_UNUSED) +{ + print_arelt_descr(outfile, abfd, verbose); +} + +void +ar_directory (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 +prompt (void) +{ + extern int interactive; + + if (interactive) + { + printf ("AR >"); + fflush (stdout); + } +} + +void +maybequit (void) +{ + if (! interactive) + xexit (9); +} + + +void +ar_open (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 (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 (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 disappear. */ + } +} + +void +ar_addmod (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 (void) +{ + if (obfd) + obfd->archive_head = 0; +} + +void +ar_delete (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 (void) +{ + if (!obfd) + { + fprintf (stderr, _("%s: no open output archive\n"), program_name); + maybequit (); + } + else + { + char *ofilename = xstrdup (bfd_get_filename (obfd)); + + bfd_close (obfd); + + smart_rename (ofilename, real_name, 0); + obfd = 0; + free (ofilename); + } +} + +void +ar_replace (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 (void) +{ + 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 (void) +{ + if (obfd) + { + bfd_cache_close (obfd); + unlink (bfd_get_filename (obfd)); + } +} + +void +ar_extract (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.17/binutils/arsup.h b/contrib/binutils-2.17/binutils/arsup.h new file mode 100644 index 0000000000..136efcf3c9 --- /dev/null +++ b/contrib/binutils-2.17/binutils/arsup.h @@ -0,0 +1,62 @@ +/* arsup.h - archive support header file + Copyright 1992, 1993, 1994, 1996, 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +struct list { + char *name; + struct list *next; +}; + +void maybequit (void); + +void prompt (void); + +void ar_clear (void); + +void ar_replace (struct list *); + +void ar_delete (struct list *); + +void ar_save (void); + +void ar_list (void); + +void ar_open (char *, int); + +void ar_directory (char *, struct list *, char *); + +void ar_addmod (struct list *); + +void ar_addlib (char *, struct list *); + +void ar_end (void); + +void ar_extract (struct list *); + +bfd *open_inarch (const char *archive_filename, const char *); + +extern int yylex (void); + +int yyparse (void); + +/* Functions from ar.c */ + +void extract_file (bfd * abfd); + +extern int interactive; diff --git a/contrib/binutils-2.17/binutils/binemul.c b/contrib/binutils-2.17/binutils/binemul.c new file mode 100644 index 0000000000..7dac32dd11 --- /dev/null +++ b/contrib/binutils-2.17/binutils/binemul.c @@ -0,0 +1,105 @@ +/* Binutils emulation layer. + Copyright 2002, 2003 Free Software Foundation, Inc. + Written by Tom Rix, Red Hat 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "binemul.h" + +extern bin_emulation_xfer_type bin_dummy_emulation; + +void +ar_emul_usage (FILE *fp) +{ + if (bin_dummy_emulation.ar_usage) + bin_dummy_emulation.ar_usage (fp); +} + +void +ar_emul_default_usage (FILE *fp) +{ + AR_EMUL_USAGE_PRINT_OPTION_HEADER (fp); + /* xgettext:c-format */ + fprintf (fp, _(" No emulation specific options\n")); +} + +bfd_boolean +ar_emul_append (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 (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 (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 (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_parse_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 (char *arg ATTRIBUTE_UNUSED) +{ + return FALSE; +} diff --git a/contrib/binutils-2.17/binutils/binemul.h b/contrib/binutils-2.17/binutils/binemul.h new file mode 100644 index 0000000000..53bbbd2de2 --- /dev/null +++ b/contrib/binutils-2.17/binutils/binemul.h @@ -0,0 +1,61 @@ +/* Binutils emulation layer. + Copyright 2002, 2003 Free Software Foundation, Inc. + Written by Tom Rix, Red Hat 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef BINEMUL_H +#define BINEMUL_H + +#include "bfd.h" +#include "bucomm.h" + +extern void ar_emul_usage (FILE *); +extern void ar_emul_default_usage (FILE *); +extern bfd_boolean ar_emul_append (bfd **, char *, bfd_boolean); +extern bfd_boolean ar_emul_default_append (bfd **, char *, bfd_boolean); +extern bfd_boolean ar_emul_replace (bfd **, char *, bfd_boolean); +extern bfd_boolean ar_emul_default_replace (bfd **, char *, bfd_boolean); +extern bfd_boolean ar_emul_parse_arg (char *); +extern bfd_boolean ar_emul_default_parse_arg (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) == 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) (FILE *fp); + bfd_boolean (* ar_append) (bfd **, char *, bfd_boolean); + bfd_boolean (* ar_replace) (bfd **, char *, bfd_boolean); + bfd_boolean (* ar_parse_arg) (char *); +} +bin_emulation_xfer_type; + +#endif diff --git a/contrib/binutils-2.17/binutils/bucomm.c b/contrib/binutils-2.17/binutils/bucomm.c new file mode 100644 index 0000000000..03a4d2873e --- /dev/null +++ b/contrib/binutils-2.17/binutils/bucomm.c @@ -0,0 +1,513 @@ +/* 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 */ +#include + +#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 (enum bfd_endian); +static int display_target_list (void); +static int display_info_table (int, int); +static int display_target_tables (void); + +/* Error reporting. */ + +char *program_name; + +void +bfd_nonfatal (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 (const char *string) +{ + bfd_nonfatal (string); + xexit (1); +} + +void +report (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 (void) +{ + /* 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 (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 (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 (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 (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 (void) +{ + 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); + enum bfd_architecture 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 = bfd_arch_obscure + 1; a < 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 (int first, int last) +{ + int t; + int ret = 1; + char *dummy_name; + enum bfd_architecture a; + + /* 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 = bfd_arch_obscure + 1; a < 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 (void) +{ + 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 (void) +{ + 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 *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 (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 (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; +} + +/* Returns the size of the named file. If the file does not + exist, or if it is not a real file, then a suitable non-fatal + error message is printed and zero is returned. */ + +off_t +get_file_size (const char * file_name) +{ + struct stat statbuf; + + if (stat (file_name, &statbuf) < 0) + { + if (errno == ENOENT) + non_fatal (_("'%s': No such file"), file_name); + else + non_fatal (_("Warning: could not locate '%s'. reason: %s"), + file_name, strerror (errno)); + } + else if (! S_ISREG (statbuf.st_mode)) + non_fatal (_("Warning: '%s' is not an ordinary file"), file_name); + else + return statbuf.st_size; + + return 0; +} + +/* Return the filename in a static buffer. */ + +const char * +bfd_get_archive_filename (bfd *abfd) +{ + static size_t curr = 0; + static char *buf; + size_t needed; + + assert (abfd != NULL); + + if (!abfd->my_archive) + return bfd_get_filename (abfd); + + 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 (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; +} diff --git a/contrib/binutils-2.17/binutils/bucomm.h b/contrib/binutils-2.17/binutils/bucomm.h new file mode 100644 index 0000000000..9f914adeb5 --- /dev/null +++ b/contrib/binutils-2.17/binutils/bucomm.h @@ -0,0 +1,226 @@ +/* bucomm.h -- binutils common include file. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2005 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _BUCOMM_H +#define _BUCOMM_H + +#include "ansidecl.h" +#include +#include + +#include "config.h" +#include "bin-bugs.h" + +#include + +#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 + +#if !HAVE_DECL_STPCPY +extern char *stpcpy (char *, const char *); +#endif + +#if !HAVE_DECL_STRSTR +extern char *strstr (); +#endif + +#ifdef HAVE_SBRK +#if !HAVE_DECL_SBRK +extern char *sbrk (); +#endif +#endif + +#if !HAVE_DECL_GETENV +extern char *getenv (); +#endif + +#if !HAVE_DECL_ENVIRON +extern char **environ; +#endif + +#if !HAVE_DECL_FPRINTF +extern int fprintf (FILE *, const char *, ...); +#endif + +#if !HAVE_DECL_SNPRINTF +extern int snprintf(char *, size_t, const char *, ...); +#endif + +#if !HAVE_DECL_VSNPRINTF +extern int vsnprintf(char *, size_t, const char *, va_list); +#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 +# ifndef ENABLE_NLS + /* The Solaris version of locale.h always includes libintl.h. If we have + been configured with --disable-nls then ENABLE_NLS will not be defined + and the dummy definitions of bindtextdomain (et al) below will conflict + with the defintions in libintl.h. So we define these values to prevent + the bogus inclusion of libintl.h. */ +# define _LIBINTL_H +# define _LIBGETTEXT_H +# endif +# 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 + +/* Used by ar.c and objcopy.c. */ +#define BUFSIZE 8192 + +/* bucomm.c */ + +/* Return the filename in a static buffer. */ +const char *bfd_get_archive_filename (bfd *); + +void bfd_nonfatal (const char *); + +void bfd_fatal (const char *) ATTRIBUTE_NORETURN; + +void report (const char *, va_list) ATTRIBUTE_PRINTF(1,0); + +void fatal (const char *, ...) ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN; + +void non_fatal (const char *, ...) ATTRIBUTE_PRINTF_1; + +void set_default_bfd_target (void); + +void list_matching_formats (char **); + +void list_supported_targets (const char *, FILE *); + +void list_supported_architectures (const char *, FILE *); + +int display_info (void); + +void print_arelt_descr (FILE *, bfd *, bfd_boolean); + +char *make_tempname (char *); + +bfd_vma parse_vma (const char *, const char *); + +off_t get_file_size (const char *); + +extern char *program_name; + +/* filemode.c */ +void mode_string (unsigned long, char *); + +/* version.c */ +extern void print_version (const char *); + +/* rename.c */ +extern void set_times (const char *, const struct stat *); + +extern int smart_rename (const char *, const char *, int); + +/* libiberty. */ +void *xmalloc (size_t); + +void *xrealloc (void *, size_t); + +#endif /* _BUCOMM_H */ diff --git a/contrib/binutils-2.17/binutils/budbg.h b/contrib/binutils-2.17/binutils/budbg.h new file mode 100644 index 0000000000..3524190a18 --- /dev/null +++ b/contrib/binutils-2.17/binutils/budbg.h @@ -0,0 +1,58 @@ +/* budbg.c -- Interfaces to the generic debugging information routines. + Copyright 1995, 1996, 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#ifndef BUDBG_H +#define BUDBG_H + +#include + +/* Routine used to read generic debugging information. */ + +extern void *read_debugging_info (bfd *, asymbol **, long); + +/* Routine used to print generic debugging information. */ + +extern bfd_boolean print_debugging_info + (FILE *, void *, bfd *, asymbol **, void *, bfd_boolean); + +/* Routines used to read and write stabs information. */ + +extern void *start_stab (void *, bfd *, bfd_boolean, asymbol **, long); + +extern bfd_boolean finish_stab (void *, void *); + +extern bfd_boolean parse_stab + (void *, void *, int, int, bfd_vma, const char *); + +extern bfd_boolean write_stabs_in_sections_debugging_info + (bfd *, void *, bfd_byte **, bfd_size_type *, bfd_byte **, bfd_size_type *); + +/* Routines used to read and write IEEE debugging information. */ + +extern bfd_boolean parse_ieee (void *, bfd *, const bfd_byte *, bfd_size_type); + +extern bfd_boolean write_ieee_debugging_info (bfd *, void *); + +/* Routine used to read COFF debugging information. */ + +extern bfd_boolean parse_coff (bfd *, asymbol **, long, void *); + +#endif diff --git a/contrib/binutils-2.17/binutils/budemang.c b/contrib/binutils-2.17/binutils/budemang.c new file mode 100644 index 0000000000..55f10b785d --- /dev/null +++ b/contrib/binutils-2.17/binutils/budemang.c @@ -0,0 +1,100 @@ +/* demangle.c -- A wrapper calling libiberty cplus_demangle + Copyright 2002, 2003, 2004 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 (bfd *abfd, const char *name) +{ + char *res, *alloc; + const char *pre, *suf; + size_t pre_len; + + 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. */ + pre = name; + while (*name == '.') + ++name; + pre_len = name - pre; + + alloc = NULL; + suf = strchr (name, '@'); + if (suf != NULL) + { + alloc = xmalloc (suf - name + 1); + memcpy (alloc, name, suf - name); + alloc[suf - name] = '\0'; + name = alloc; + } + + res = cplus_demangle (name, DMGL_ANSI | DMGL_PARAMS); + if (res != NULL) + { + /* Now put back any suffix, or stripped dots. */ + if (pre_len != 0 || suf != NULL) + { + size_t len; + size_t suf_len; + char *final; + + if (alloc != NULL) + free (alloc); + + len = strlen (res); + if (suf == NULL) + suf = res + len; + suf_len = strlen (suf) + 1; + final = xmalloc (pre_len + len + suf_len); + + memcpy (final, pre, pre_len); + memcpy (final + pre_len, res, len); + memcpy (final + pre_len + len, suf, suf_len); + free (res); + res = final; + } + + return res; + } + + if (alloc != NULL) + free (alloc); + + return xstrdup (pre); +} diff --git a/contrib/binutils-2.17/binutils/budemang.h b/contrib/binutils-2.17/binutils/budemang.h new file mode 100644 index 0000000000..17df9f55ea --- /dev/null +++ b/contrib/binutils-2.17/binutils/budemang.h @@ -0,0 +1,25 @@ +/* demangle.h -- A wrapper calling libiberty cplus_demangle + Copyright 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ +#ifndef BUDEMANG_H +#define BUDEMANG_H + +char *demangle (bfd *, const char *); + +#endif diff --git a/contrib/binutils-2.17/binutils/config.in b/contrib/binutils-2.17/binutils/config.in new file mode 100644 index 0000000000..93d8e95283 --- /dev/null +++ b/contrib/binutils-2.17/binutils/config.in @@ -0,0 +1,267 @@ +/* config.in. Generated from configure.in by autoheader. */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +#undef CRAY_STACKSEG_END + +/* Define to 1 if using `alloca.c'. */ +#undef C_ALLOCA + +/* Define to 1 if NLS is requested */ +#undef ENABLE_NLS + +/* Suffix used for executables, if any. */ +#undef EXECUTABLE_SUFFIX + +/* Define to 1 if you have `alloca', as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#undef HAVE_ALLOCA_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARGZ_H + +/* Define to 1 if you have the `dcgettext' function. */ +#undef HAVE_DCGETTEXT + +/* Define to 1 if you have the declaration of `environ', and to 0 if you + don't. */ +#undef HAVE_DECL_ENVIRON + +/* Define to 1 if you have the declaration of `fprintf', and to 0 if you + don't. */ +#undef HAVE_DECL_FPRINTF + +/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you + don't. */ +#undef HAVE_DECL_GETC_UNLOCKED + +/* Define to 1 if you have the declaration of `getenv', and to 0 if you don't. + */ +#undef HAVE_DECL_GETENV + +/* Is the prototype for getopt in in the expected format? */ +#undef HAVE_DECL_GETOPT + +/* Define to 1 if you have the declaration of `sbrk', and to 0 if you don't. + */ +#undef HAVE_DECL_SBRK + +/* Define to 1 if you have the declaration of `snprintf', and to 0 if you + don't. */ +#undef HAVE_DECL_SNPRINTF + +/* Define to 1 if you have the declaration of `stpcpy', and to 0 if you don't. + */ +#undef HAVE_DECL_STPCPY + +/* Define to 1 if you have the declaration of `strstr', and to 0 if you don't. + */ +#undef HAVE_DECL_STRSTR + +/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you + don't. */ +#undef HAVE_DECL_VSNPRINTF + +/* Does the platform use an executable suffix? */ +#undef HAVE_EXECUTABLE_SUFFIX + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Is fopen64 available? */ +#undef HAVE_FOPEN64 + +/* Define to 1 if you have the `getcwd' function. */ +#undef HAVE_GETCWD + +/* Define to 1 if you have the `getc_unlocked' function. */ +#undef HAVE_GETC_UNLOCKED + +/* Define to 1 if you have the `getpagesize' function. */ +#undef HAVE_GETPAGESIZE + +/* Define as 1 if you have gettext and don't want to use GNU gettext. */ +#undef HAVE_GETTEXT + +/* Does define struct utimbuf? */ +#undef HAVE_GOOD_UTIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define if your locale.h file contains LC_MESSAGES. */ +#undef HAVE_LC_MESSAGES + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the `munmap' function. */ +#undef HAVE_MUNMAP + +/* Define to 1 if you have the header file. */ +#undef HAVE_NL_TYPES_H + +/* Define to 1 if you have the `putenv' function. */ +#undef HAVE_PUTENV + +/* Define to 1 if you have the `sbrk' function. */ +#undef HAVE_SBRK + +/* Define to 1 if you have the `setenv' function. */ +#undef HAVE_SETENV + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* Define to 1 if you have the `setmode' function. */ +#undef HAVE_SETMODE + +/* Is stat64 available? */ +#undef HAVE_STAT64 + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the stpcpy function */ +#undef HAVE_STPCPY + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strcoll' function. */ +#undef HAVE_STRCOLL + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FILE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Is the type time_t defined in ? */ +#undef HAVE_TIME_T_IN_TIME_H + +/* Is the type time_t defined in ? */ +#undef HAVE_TIME_T_IN_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `utimes' function. */ +#undef HAVE_UTIMES + +/* Define to 1 if you have the header file. */ +#undef HAVE_VALUES_H + +/* Define to 1 if you have the `__argz_count' function. */ +#undef HAVE___ARGZ_COUNT + +/* Define to 1 if you have the `__argz_next' function. */ +#undef HAVE___ARGZ_NEXT + +/* Define to 1 if you have the `__argz_stringify' function. */ +#undef HAVE___ARGZ_STRINGIFY + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +#undef STACK_DIRECTION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Configured target name. */ +#undef TARGET + +/* Define to 1 if user symbol names have a leading underscore, 0 if not. */ +#undef TARGET_PREPENDS_UNDERSCORE + +/* Use b modifier when opening binary files? */ +#undef USE_BINARY_FOPEN + +/* Version number of package */ +#undef VERSION + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER + +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif + +/* Enable LFS */ +#undef _LARGEFILE64_SOURCE + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to `long' if does not define. */ +#undef off_t + +/* Define to `unsigned' if does not define. */ +#undef size_t diff --git a/contrib/binutils-2.17/binutils/debug.c b/contrib/binutils-2.17/binutils/debug.c new file mode 100644 index 0000000000..07d38acfe4 --- /dev/null +++ b/contrib/binutils-2.17/binutils/debug.c @@ -0,0 +1,3373 @@ +/* debug.c -- Handle generic debugging information. + Copyright 1995, 1996, 1997, 1998, 1999, 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 converter 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 (const char *); +static struct debug_name *debug_add_to_namespace + (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 + (struct debug_handle *, const char *, enum debug_object_kind, + enum debug_object_linkage); +static struct debug_type *debug_make_type + (struct debug_handle *, enum debug_type_kind, unsigned int); +static struct debug_type *debug_get_real_type + (void *, debug_type, struct debug_type_real_list *); +static bfd_boolean debug_write_name + (struct debug_handle *, const struct debug_write_fns *, void *, + struct debug_name *); +static bfd_boolean debug_write_type + (struct debug_handle *, const struct debug_write_fns *, void *, + struct debug_type *, struct debug_name *); +static bfd_boolean debug_write_class_type + (struct debug_handle *, const struct debug_write_fns *, void *, + struct debug_type *, const char *); +static bfd_boolean debug_write_function + (struct debug_handle *, const struct debug_write_fns *, void *, + const char *, enum debug_object_linkage, struct debug_function *); +static bfd_boolean debug_write_block + (struct debug_handle *, const struct debug_write_fns *, void *, + struct debug_block *); +static bfd_boolean debug_write_linenos + (struct debug_handle *, const struct debug_write_fns *, void *, bfd_vma); +static bfd_boolean debug_set_class_id + (struct debug_handle *, const char *, struct debug_type *); +static bfd_boolean debug_type_samep + (struct debug_handle *, struct debug_type *, struct debug_type *); +static bfd_boolean debug_class_type_samep + (struct debug_handle *, struct debug_type *, struct debug_type *); + +/* Issue an error message. */ + +static void +debug_error (const char *message) +{ + fprintf (stderr, "%s\n", message); +} + +/* Add an object to a namespace. */ + +static struct debug_name * +debug_add_to_namespace (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 (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. */ + +void * +debug_init (void) +{ + struct debug_handle *ret; + + ret = (struct debug_handle *) xmalloc (sizeof *ret); + memset (ret, 0, sizeof *ret); + return (void *) ret; +} + +/* Set the source filename. This implicitly starts a new compilation + unit. */ + +bfd_boolean +debug_set_filename (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *handle, const struct debug_write_fns *fns, void *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 (struct debug_handle *info, + const struct debug_write_fns *fns, void *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 (struct debug_handle *info, + const struct debug_write_fns *fns, void *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 ((void *) 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 (struct debug_handle *info, + const struct debug_write_fns *fns, void *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 (struct debug_handle *info, + const struct debug_write_fns *fns, void *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 (struct debug_handle *info, + const struct debug_write_fns *fns, void *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 (struct debug_handle *info, + const struct debug_write_fns *fns, void *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 (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 (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 (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 ((void *) info, + f1->type, NULL), + debug_get_real_type ((void *) 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.17/binutils/debug.h b/contrib/binutils-2.17/binutils/debug.h new file mode 100644 index 0000000000..c18ba54a66 --- /dev/null +++ b/contrib/binutils-2.17/binutils/debug.h @@ -0,0 +1,792 @@ +/* debug.h -- Describe generic debugging information. + Copyright 1995, 1996, 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 converter 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) (void *, 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) (void *, 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) (void *); + + /* Push a void type onto the type stack. */ + bfd_boolean (*void_type) (void *); + + /* Push an integer type onto the type stack, given the size and + whether it is unsigned. */ + bfd_boolean (*int_type) (void *, unsigned int, bfd_boolean); + + /* Push a floating type onto the type stack, given the size. */ + bfd_boolean (*float_type) (void *, unsigned int); + + /* Push a complex type onto the type stack, given the size. */ + bfd_boolean (*complex_type) (void *, unsigned int); + + /* Push a bfd_boolean type onto the type stack, given the size. */ + bfd_boolean (*bool_type) (void *, 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) + (void *, 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) (void *); + + /* 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) (void *, 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) (void *); + + /* 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) (void *, 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) + (void *, 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) (void *, 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) (void *); + + /* 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) (void *, 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) (void *); + + /* 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) (void *); + + /* 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) + (void *, 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) + (void *, 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) (void *); + + /* 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) + (void *, 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) + (void *, 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) + (void *, 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) (void *, 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) + (void *, 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) + (void *, const char *, enum debug_visibility, bfd_boolean, + bfd_boolean); + + /* Finish describing a class method. */ + bfd_boolean (*class_end_method) (void *); + + /* Finish describing a class, and push it onto the type stack. */ + bfd_boolean (*end_class_type) (void *); + + /* Push a type on the stack which was given a name by an earlier + call to typdef. */ + bfd_boolean (*typedef_type) (void *, 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) + (void *, const char *, unsigned int, enum debug_type_kind); + + /* Pop the type stack, and typedef it to the given name. */ + bfd_boolean (*typdef) (void *, 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) (void *, const char *); + + /* This is called to record a named integer constant. */ + bfd_boolean (*int_constant) (void *, const char *, bfd_vma); + + /* This is called to record a named floating point constant. */ + bfd_boolean (*float_constant) (void *, const char *, double); + + /* This is called to record a typed integer constant. The type is + popped off the type stack. */ + bfd_boolean (*typed_constant) (void *, const char *, bfd_vma); + + /* This is called to record a variable. The type is popped off the + type stack. */ + bfd_boolean (*variable) + (void *, 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) (void *, const char *, bfd_boolean); + + /* Record a function parameter for the current function. The type + must be popped off the stack. */ + bfd_boolean (*function_parameter) + (void *, 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) (void *, bfd_vma); + + /* Finish writing out a block. The argument is the ending address + of the block. */ + bfd_boolean (*end_block) (void *, bfd_vma); + + /* Finish writing out a function. */ + bfd_boolean (*end_function) (void *); + + /* Record line number information for the current compilation unit. */ + bfd_boolean (*lineno) (void *, 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 void *debug_init (void); + +/* Set the source filename. This implicitly starts a new compilation + unit. */ + +extern bfd_boolean debug_set_filename (void *, 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 (void *, 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 + (void *, const char *, debug_type, bfd_boolean, bfd_vma); + +/* Record a parameter for the current function. */ + +extern bfd_boolean debug_record_parameter + (void *, 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 (void *, 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 (void *, 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 (void *, bfd_vma); + +/* Associate a line number in the current source file with a given + address. */ + +extern bfd_boolean debug_record_line (void *, 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 (void *, const char *); + +/* End a named common block. */ + +extern bfd_boolean debug_end_common_block (void *, const char *); + +/* Record a named integer constant. */ + +extern bfd_boolean debug_record_int_const (void *, const char *, bfd_vma); + +/* Record a named floating point constant. */ + +extern bfd_boolean debug_record_float_const (void *, const char *, double); + +/* Record a typed constant with an integral value. */ + +extern bfd_boolean debug_record_typed_const + (void *, const char *, debug_type, bfd_vma); + +/* Record a label. */ + +extern bfd_boolean debug_record_label + (void *, const char *, debug_type, bfd_vma); + +/* Record a variable. */ + +extern bfd_boolean debug_record_variable + (void *, 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 + (void *, debug_type *, const char *); + +/* Make a void type. */ + +extern debug_type debug_make_void_type (void *); + +/* 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 (void *, 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 (void *, unsigned int); + +/* Make a boolean type of a given size. */ + +extern debug_type debug_make_bool_type (void *, unsigned int); + +/* Make a complex type of a given size. */ + +extern debug_type debug_make_complex_type (void *, 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 + (void *, 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 + (void *, 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 + (void *, const char **, bfd_signed_vma *); + +/* Make a pointer to a given type. */ + +extern debug_type debug_make_pointer_type (void *, 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 + (void *, debug_type, debug_type *, bfd_boolean); + +/* Make a reference to a given type. */ + +extern debug_type debug_make_reference_type (void *, debug_type); + +/* Make a range of a given type from a lower to an upper bound. */ + +extern debug_type debug_make_range_type + (void *, 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 + (void *, 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 (void *, 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 (void *, 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 + (void *, debug_type, debug_type, debug_type *, bfd_boolean); + +/* Make a const qualified version of a given type. */ + +extern debug_type debug_make_const_type (void *, debug_type); + +/* Make a volatile qualified version of a given type. */ + +extern debug_type debug_make_volatile_type (void *, 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 + (void *, 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 + (void *, 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 + (void *, 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 + (void *, 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 + (void *, 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 + (void *, 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 + (void *, 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 (void *, 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 (void *, const char *, debug_type); + +/* Record the size of a given type. */ + +extern bfd_boolean debug_record_type_size (void *, debug_type, unsigned int); + +/* Find a named type. */ + +extern debug_type debug_find_named_type (void *, const char *); + +/* Find a tagged type. */ + +extern debug_type debug_find_tagged_type + (void *, const char *, enum debug_type_kind); + +/* Get the kind of a type. */ + +extern enum debug_type_kind debug_get_type_kind (void *, debug_type); + +/* Get the name of a type. */ + +extern const char *debug_get_type_name (void *, debug_type); + +/* Get the size of a type. */ + +extern bfd_vma debug_get_type_size (void *, debug_type); + +/* Get the return type of a function or method type. */ + +extern debug_type debug_get_return_type (void *, 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 + (void *, 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 (void *, debug_type); + +/* Get the NULL terminated array of fields for a struct, union, or + class. */ + +extern const debug_field *debug_get_fields (void *, debug_type); + +/* Get the type of a field. */ + +extern debug_type debug_get_field_type (void *, debug_field); + +/* Get the name of a field. */ + +extern const char *debug_get_field_name (void *, 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 (void *, 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 (void *, debug_field); + +/* Get the visibility of a field. */ + +extern enum debug_visibility debug_get_field_visibility (void *, 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 (void *, 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 void * is the debugging handle. The second void * is a handle + which is passed to the functions. */ + +extern bfd_boolean debug_write + (void *, const struct debug_write_fns *, void *); + +#endif /* DEBUG_H */ diff --git a/contrib/binutils-2.17/binutils/doc/addr2line.1 b/contrib/binutils-2.17/binutils/doc/addr2line.1 new file mode 100644 index 0000000000..71d1ea7639 --- /dev/null +++ b/contrib/binutils-2.17/binutils/doc/addr2line.1 @@ -0,0 +1,265 @@ +.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 +.\" +.\" 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. \*(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- +.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 "2006-06-23" "binutils-2.17" "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\-i\fR|\fB\-\-inlines\fR] + [\fB\-j\fR|\fB\-\-section=\fR\fIname\fR] + [\fB\-H\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] + [addr addr ...] +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBaddr2line\fR translates addresses into file names and line numbers. +Given an address in an executable or an offset in a section of a relocatable +object, it uses the debugging information to figure out which file name and +line number are associated with it. +.PP +The executable or relocatable object to use is specified with the \fB\-e\fR +option. The default is the file \fIa.out\fR. The section in the relocatable +object to use is specified with the \fB\-j\fR option. +.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. +.IP "\fB\-i\fR" 4 +.IX Item "-i" +.PD 0 +.IP "\fB\-\-inlines\fR" 4 +.IX Item "--inlines" +.PD +If the address belongs to a function that was inlined, the source +information for all enclosing scopes back to the first non-inlined +function will also be printed. For example, if \f(CW\*(C`main\*(C'\fR inlines +\&\f(CW\*(C`callee1\*(C'\fR which inlines \f(CW\*(C`callee2\*(C'\fR, and address is from +\&\f(CW\*(C`callee2\*(C'\fR, the source information for \f(CW\*(C`callee1\*(C'\fR and \f(CW\*(C`main\*(C'\fR +will also be printed. +.IP "\fB\-j\fR" 4 +.IX Item "-j" +.PD 0 +.IP "\fB\-\-section\fR" 4 +.IX Item "--section" +.PD +Read offsets relative to the specified section instead of absolute addresses. +.IP "\fB@\fR\fIfile\fR" 4 +.IX Item "@file" +Read command-line options from \fIfile\fR. The options read are +inserted in place of the original @\fIfile\fR option. If \fIfile\fR +does not exist, or cannot be read, then the option will be treated +literally, and not removed. +.Sp +Options in \fIfile\fR are separated by whitespace. A whitespace +character may be included in an option by surrounding the entire +option in either single or double quotes. Any character (including a +backslash) may be included by prefixing the character to be included +with a backslash. The \fIfile\fR may itself contain additional +@\fIfile\fR options; any such options will be processed recursively. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +Info entries for \fIbinutils\fR. +.SH "COPYRIGHT" +.IX Header "COPYRIGHT" +Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +2000, 2001, 2002, 2003, 2004, 2005, 2006 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 \*(L"\s-1GNU\s0 Free Documentation License\*(R". diff --git a/contrib/binutils-2.17/binutils/doc/ar.1 b/contrib/binutils-2.17/binutils/doc/ar.1 new file mode 100644 index 0000000000..5985ca15e4 --- /dev/null +++ b/contrib/binutils-2.17/binutils/doc/ar.1 @@ -0,0 +1,390 @@ +.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 +.\" +.\" 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. \*(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- +.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 "2006-06-23" "binutils-2.17" "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 \*(L"librarian\*(R" +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. +.IP "\fB@\fR\fIfile\fR" 4 +.IX Item "@file" +Read command-line options from \fIfile\fR. The options read are +inserted in place of the original @\fIfile\fR option. If \fIfile\fR +does not exist, or cannot be read, then the option will be treated +literally, and not removed. +.Sp +Options in \fIfile\fR are separated by whitespace. A whitespace +character may be included in an option by surrounding the entire +option in either single or double quotes. Any character (including a +backslash) may be included by prefixing the character to be included +with a backslash. The \fIfile\fR may itself contain additional +@\fIfile\fR options; any such options will be processed recursively. +.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, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +2000, 2001, 2002, 2003, 2004, 2005, 2006 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 \*(L"\s-1GNU\s0 Free Documentation License\*(R". diff --git a/contrib/binutils-2.17/binutils/doc/binutils.texi b/contrib/binutils-2.17/binutils/doc/binutils.texi new file mode 100644 index 0000000000..be571d2a7c --- /dev/null +++ b/contrib/binutils-2.17/binutils/doc/binutils.texi @@ -0,0 +1,3907 @@ +\input texinfo @c -*- Texinfo -*- +@setfilename binutils.info +@c Copyright 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + +@c man begin INCLUDE +@include config.texi +@c man end + +@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, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +2000, 2001, 2002, 2003, 2004, 2005, 2006 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, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +@c 2000, 2001, 2002, 2003, 2004, 2005, 2006 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 @value{UPDATED} +@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, 1992, 1993, 1994, 1995, 1996, 1997, 1998, +2000, 2001, 2002, 2003, 2004, 2005, 2006 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 +* Common Options:: Command-line options for all utilities +* 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{--special-syms}] + [@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 symbol is determined in a system-specific manner without +error. On some systems, uppercase indicates that a default value has been +specified. + + +@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 --special-syms +Display symbols which have a target-specific special meaning. These +symbols are usually used by the target for some special processing and +are not normally helpful when included included in the normal symbol +lists. For example for ARM targets this option would skip the mapping +symbols used to mark transistions between ARM code, THUMB code and +data. + +@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{--strip-unneeded-symbol=}@var{symbolname}] + [@option{-G} @var{symbolname}|@option{--keep-global-symbol=}@var{symbolname}] + [@option{-L} @var{symbolname}|@option{--localize-symbol=}@var{symbolname}] + [@option{--globalize-symbol=}@var{symbolname}] + [@option{-W} @var{symbolname}|@option{--weaken-symbol=}@var{symbolname}] + [@option{-w}|@option{--wildcard}] + [@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{--redefine-syms=}@var{filename}] + [@option{--weaken}] + [@option{--keep-symbols=}@var{filename}] + [@option{--strip-symbols=}@var{filename}] + [@option{--strip-unneeded-symbols=}@var{filename}] + [@option{--keep-global-symbols=}@var{filename}] + [@option{--localize-symbols=}@var{filename}] + [@option{--globalize-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{--add-gnu-debuglink=}@var{path-to-file}] + [@option{--keep-file-symbols}] + [@option{--only-keep-debug}] + [@option{--writable-text}] + [@option{--readonly-text}] + [@option{--pure}] + [@option{--impure}] + [@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 or sections 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} +When stripping symbols, keep symbol @var{symbolname} even if it would +normally be stripped. 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 --strip-unneeded-symbol=@var{symbolname} +Do not copy symbol @var{symbolname} from the source file unless it is needed +by a relocation. 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 --globalize-symbol=@var{symbolname} +Give symbol @var{symbolname} global scoping so that it is visible +outside of the file in which it is defined. This option may be given +more than once. + +@item -w +@itemx --wildcard +Permit regular expressions in @var{symbolname}s used in other command +line options. The question mark (?), asterisk (*), backslash (\) and +square brackets ([]) operators can be used anywhere in the symbol +name. If the first character of the symbol name is the exclamation +point (!) then the sense of the switch is reversed for that symbol. +For example: + +@smallexample + -w -W !foo -W fo* +@end smallexample + +would cause objcopy to weaken all symbols that start with ``fo'' +except for the symbol ``foo''. + +@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 --redefine-syms=@var{filename} +Apply @option{--redefine-sym} to each symbol pair "@var{old} @var{new}" +listed in the file @var{filename}. @var{filename} is simply a flat file, +with one symbol pair per line. Line comments may be introduced by the hash +character. This option may be given more than once. + +@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 --strip-unneeded-symbols=@var{filename} +Apply @option{--strip-unneeded-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 --globalize-symbols=@var{filename} +Apply @option{--globalize-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. For ELF based architectures if the @var{index} +alternative does not exist then the value is treated as an absolute +number to be stored in the e_machine field of the ELF header. + +@item --writable-text +Mark the output text as writable. This option isn't meaningful for all +object file formats. + +@item --readonly-text +Make the output text write protected. This option isn't meaningful for all +object file formats. + +@item --pure +Mark the output file as demand paged. This option isn't meaningful for all +object file formats. + +@item --impure +Mark the output file as impure. This option isn't meaningful for all +object file formats. + +@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 --add-gnu-debuglink=@var{path-to-file} +Creates a .gnu_debuglink section which contains a reference to @var{path-to-file} +and adds it to the output file. + +@item --keep-file-symbols +When stripping a file, perhaps with @option{--strip-debug} or +@option{--strip-unneeded}, retain any symbols specifying source file names, +which would otherwise get stripped. + +@item --only-keep-debug +Strip a file, removing contents of any sections that would not be +stripped by @option{--strip-debug} and leaving the debugging sections +intact. + +The intention is that this option will be used in conjunction with +@option{--add-gnu-debuglink} to create a two part executable. One a +stripped binary which will occupy less space in RAM and in a +distribution and the second a debugging information file which is only +needed if debugging abilities are required. The suggested procedure +to create these files is as follows: + +@enumerate +@item Link the executable as normal. Assuming that is is called +@code{foo} then... +@item Run @code{objcopy --only-keep-debug foo foo.dbg} to +create a file containing the debugging info. +@item Run @code{objcopy --strip-debug foo} to create a +stripped executable. +@item Run @code{objcopy --add-gnu-debuglink=foo.dbg foo} +to add a link to the debugging info into the stripped executable. +@end enumerate + +Note - the choice of @code{.dbg} as an extension for the debug info +file is arbitrary. Also the @code{--only-keep-debug} step is +optional. You could instead do this: + +@enumerate +@item Link the executable as normal. +@item Copy @code{foo} to @code{foo.full} +@item Run @code{objcopy --strip-debug foo} +@item Run @code{objcopy --add-gnu-debuglink=foo.full foo} +@end enumerate + +i.e. the file pointed to by the @option{--add-gnu-debuglink} can be the +full executable. It does not have to be a file created by the +@option{--only-keep-debug} switch. + +@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{-e}|@option{--debugging-tags}] + [@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{-W}|@option{--dwarf}] + [@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{--special-syms}] + [@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,-e,-f,-g,-G,-h,-H,-p,-r,-R,-s,-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 -e +@itemx --debugging-tags +Like @option{-g}, but the information is generated in a format compatible +with ctags tool. + +@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 it is necessary to specify more than one +disassembler option then multiple @option{-M} options can be used or +can be placed together into a comma separated list. + +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-names-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. @option{e300} selects +disassembly for the e300 family. + +For MIPS, this option controls the printing of instruction mneumonic +names and 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 no-aliases +Print the 'raw' instruction mneumonic instead of some pseudo +instruction mneumonic. I.E. print 'daddu' or 'or' instead of 'move', +'sll' instead of 'nop', etc. + +@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. + +For VAX, you can specify function entry addresses with @option{-M +entry:0xf00ba}. You can use this multiple times to properly +disassemble VAX binary files that don't contain symbol tables (like +ROM dumps). In these cases, the function entry mask would otherwise +be decoded as VAX instructions, which would probably lead the the rest +of the function being wrongly disassembled. + +@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. By default all +non-empty sections are displayed. + +@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 -W +@itemx --dwarf +@cindex DWARF +@cindex debug symbols +Displays the contents of the DWARF debug sections in the file, if any +are present. + +@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 --special-syms +When displaying symbols include those which the target considers to be +special in some way and which would not normally be of interest to the +user. + +@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 -p -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{-w}|@option{--wildcard}] + [@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{--keep-file-symbols}] + [@option{--only-keep-debug}] + [@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} +When stripping symbols, keep symbol @var{symbolname} even if it would +normally be stripped. 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 -w +@itemx --wildcard +Permit regular expressions in @var{symbolname}s used in other command +line options. The question mark (?), asterisk (*), backslash (\) and +square brackets ([]) operators can be used anywhere in the symbol +name. If the first character of the symbol name is the exclamation +point (!) then the sense of the switch is reversed for that symbol. +For example: + +@smallexample + -w -K !foo -K fo* +@end smallexample + +would cause strip to only keep symbols that start with the letters +``fo'', but to discard the symbol ``foo''. + +@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 --keep-file-symbols +When stripping a file, perhaps with @option{--strip-debug} or +@option{--strip-unneeded}, retain any symbols specifying source file names, +which would otherwise get stripped. + +@item --only-keep-debug +Strip a file, removing any sections that would be stripped by +@option{--strip-debug} and leaving the debugging sections. + +The intention is that this option will be used in conjunction with +@option{--add-gnu-debuglink} to create a two part executable. One a +stripped binary which will occupy less space in RAM and in a +distribution and the second a debugging information file which is only +needed if debugging abilities are required. The suggested procedure +to create these files is as follows: + +@enumerate +@item Link the executable as normal. Assuming that is is called +@code{foo} then... +@item Run @code{objcopy --only-keep-debug foo foo.dbg} to +create a file containing the debugging info. +@item Run @code{objcopy --strip-debug foo} to create a +stripped executable. +@item Run @code{objcopy --add-gnu-debuglink=foo.dbg foo} +to add a link to the debugging info into the stripped executable. +@end enumerate + +Note - the choice of @code{.dbg} as an extension for the debug info +file is arbitrary. Also the @code{--only-keep-debug} step is +optional. You could instead do this: + +@enumerate +@item Link the executable as normal. +@item Copy @code{foo} to @code{foo.full} +@item Run @code{strip --strip-debug foo} +@item Run @code{objcopy --add-gnu-debuglink=foo.full foo} +@end enumerate + +ie the file pointed to by the @option{--add-gnu-debuglink} can be the +full executable. It does not have to be a file created by the +@option{--only-keep-debug} switch. + +@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{-n}|@option{--no-strip-underscores}] + [@option{-p}|@option{--no-params}] + [@option{-t}|@option{--types}] + [@option{-i}|@option{--no-verbose}] + [@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 provide function overloading, which means +that you can write many functions with the same name, providing that +each function takes parameters of different types. In order to be +able to distinguish these similarly named functions C++ and Java +encode them into a low-level assembler name which uniquely identifies +each different version. 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 they can be read. + +Every alphanumeric word (consisting of letters, digits, underscores, +dollars, or periods) seen in the input is a potential mangled name. +If the name decodes into a C++ name, the C++ name replaces the +low-level name in the output, otherwise the original word is output. +In this way you can pass an entire assembler source file, containing +mangled names, through @command{c++filt} and see the same source file +containing demangled names. + +You can also use @command{c++filt} to decipher individual symbols by +passing them on the command line: + +@example +c++filt @var{symbol} +@end example + +If no @var{symbol} arguments are given, @command{c++filt} reads symbol +names from the standard input instead. All the results are printed on +the standard output. The difference between reading names from the +command line versus reading names from the standard input is that +command line arguments are expected to be just mangled names and no +checking is performed to seperate them from surrounding text. Thus +for example: + +@smallexample +c++filt -n _Z1fv +@end smallexample + +will work and demangle the name to ``f()'' whereas: + +@smallexample +c++filt -n _Z1fv, +@end smallexample + +will not work. (Note the extra comma at the end of the mangled +name which makes it invalid). This command however will work: + +@smallexample +echo _Z1fv, | c++filt -n +@end smallexample + +and will display ``f(),'' ie the demangled name followed by a +trailing comma. This behaviour is because when the names are read +from the standard input it is expected that they might be part of an +assembler source file where there might be extra, extraneous +characters trailing after a mangled name. eg: + +@smallexample + .type _Z1fv, @@function +@end smallexample + +@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 -p +@itemx --no-params +When demangling the name of a function, do not display the types of +the function's parameters. + +@item -t +@itemx --types +Attempt to demangle types as well as function names. This is disabled +by default since mangled types are normally only used internally in +the compiler, and they can be confused with non-mangled names. eg +a function called ``a'' treated as a mangled type name would be +demangled to ``signed char''. + +@item -i +@itemx --no-verbose +Do not include implementation details (if any) in the demangled +output. + +@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{-i}|@option{--inlines}] + [@option{-j}|@option{--section=}@var{name}] + [@option{-H}|@option{--help}] [@option{-V}|@option{--version}] + [addr addr @dots{}] +@c man end +@end smallexample + +@c man begin DESCRIPTION addr2line + +@command{addr2line} translates addresses into file names and line numbers. +Given an address in an executable or an offset in a section of a relocatable +object, it uses the debugging information to figure out which file name and +line number are associated with it. + +The executable or relocatable object to use is specified with the @option{-e} +option. The default is the file @file{a.out}. The section in the relocatable +object to use is specified with the @option{-j} option. + +@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. + +@item -i +@itemx --inlines +If the address belongs to a function that was inlined, the source +information for all enclosing scopes back to the first non-inlined +function will also be printed. For example, if @code{main} inlines +@code{callee1} which inlines @code{callee2}, and address is from +@code{callee2}, the source information for @code{callee1} and @code{main} +will also be printed. + +@item -j +@itemx --section +Read offsets relative to the specified section instead of absolute addresses. +@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 dlltool +@cindex DLL +@kindex dlltool + +@command{dlltool} is used to create the files needed to create dynamic +link libraries (DLLs) on systems which understand PE format image +files such as Windows. A DLL contains an export table which contains +information that the runtime loader needs to resolve references from a +referencing program. + +The export table is generated by this program by reading in a +@file{.def} file or scanning the @file{.a} and @file{.o} files which +will be in the DLL. A @file{.o} file can contain information in +special @samp{.drectve} sections with export information. + +@quotation +@emph{Note:} @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{--add-stdcall-underscore}] + [@option{-k}|@option{--kill-at}] [@option{-A}|@option{--add-stdcall-alias}] + [@option{-p}|@option{--ext-prefix-alias} @var{prefix}] + [@option{-x}|@option{--no-idata4}] [@option{-c}|@option{--no-idata5}] [@option{-i}|@option{--interwork}] + [@option{-n}|@option{--nodelete}] [@option{-t}|@option{--temp-prefix} @var{prefix}] + [@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 @file{.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 @file{.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 @file{.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 @file{.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 @file{.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 @file{.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 @file{.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 @file{.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 @emph{all} exported symbols. + +@item --add-stdcall-underscore +Specifies that when @command{dlltool} is creating the exports file it +should prepend an underscore to the names of exported @emph{stdcall} +functions. Variable names and non-stdcall function names are not modified. +This option is useful when creating GNU-compatible import libs for third +party DLLs that were built with MS-Windows tools. + +@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 -p +@itemx --ext-prefix-alias @var{prefix} +Causes @command{dlltool} to create external aliases for all DLL +imports with the specified prefix. The aliases are created for both +external and import symbols with no leading underscore. + +@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 -t @var{prefix} +@itemx --temp-prefix @var{prefix} +Makes @command{dlltool} use @var{prefix} when constructing the names of +temporary assembler and object files. By default, the temp file prefix +is generated from the pid. + +@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 + +@menu +* def file format:: The format of the dlltool @file{.def} file +@end menu + +@node def file format +@section The format of the @command{dlltool} @file{.def} file + +A @file{.def} file contains any number of the following commands: + +@table @asis + +@item @code{NAME} @var{name} @code{[ ,} @var{base} @code{]} +The result is going to be named @var{name}@code{.exe}. + +@item @code{LIBRARY} @var{name} @code{[ ,} @var{base} @code{]} +The result is going to be named @var{name}@code{.dll}. + +@item @code{EXPORTS ( ( (} @var{name1} @code{[ = } @var{name2} @code{] ) | ( } @var{name1} @code{=} @var{module-name} @code{.} @var{external-name} @code{) )} +@item @code{[} @var{integer} @code{] [ NONAME ] [ CONSTANT ] [ DATA ] [ PRIVATE ] ) *} +Declares @var{name1} as an exported symbol from the DLL, with optional +ordinal number @var{integer}, or declares @var{name1} as an alias +(forward) of the function @var{external-name} in the DLL +@var{module-name}. + +@item @code{IMPORTS ( (} @var{internal-name} @code{=} @var{module-name} @code{.} @var{integer} @code{) | [} @var{internal-name} @code{= ]} @var{module-name} @code{.} @var{external-name} @code{) ) *} +Declares that @var{external-name} or the exported function whose +ordinal number is @var{integer} is to be imported from the file +@var{module-name}. If @var{internal-name} is specified then this is +the name that the imported function will be referred to in the body of +the DLL. + +@item @code{DESCRIPTION} @var{string} +Puts @var{string} into the output @file{.exp} file in the +@code{.rdata} section. + +@item @code{STACKSIZE} @var{number-reserve} @code{[, } @var{number-commit} @code{]} +@item @code{HEAPSIZE} @var{number-reserve} @code{[, } @var{number-commit} @code{]} +Generates @code{--stack} or @code{--heap} +@var{number-reserve},@var{number-commit} in the output @code{.drectve} +section. The linker will see this and act upon it. + +@item @code{CODE} @var{attr} @code{+} +@item @code{DATA} @var{attr} @code{+} +@item @code{SECTIONS (} @var{section-name} @var{attr}@code{ + ) *} +Generates @code{--attr} @var{section-name} @var{attr} in the output +@code{.drectve} section, where @var{attr} is one of @code{READ}, +@code{WRITE}, @code{EXECUTE} or @code{SHARED}. The linker will see +this and act upon it. + +@end table + +@ignore +@c man begin SEEALSO dlltool +The Info pages 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{-g}|@option{--section-groups}] + [@option{-t}|@option{--section-details}] + [@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[liaprmfFsoR]}| + @option{--debug-dump}[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges]] + [@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. 32-bit and +64-bit ELF files are supported, as are archives containing ELF files. + +This program performs a similar function to @command{objdump} but it +goes into more detail and it exists independently of the @sc{bfd} +library, so if there is a bug in @sc{bfd} then readelf will not be +affected. + +@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 -g +@itemx --section-groups +@cindex ELF section group information +Displays the information contained in the file's section groups, if it +has any. + +@item -t +@itemx --section-details +@cindex ELF section information +Displays the detailed section information. Implies @option{-S}. + +@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 notes +Displays the contents of the NOTE segments and/or sections, if any. + +@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 -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. +A number identifies a particular section by index in the section table; +any other string identifies all sections with that name in the object file. + +@item -w[liaprmfFsoR] +@itemx --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges] +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 Common Options +@chapter Common Options + +The following command-line options are supported by all of the +programs described in this manual. + +@c man begin OPTIONS +@table @env +@include at-file.texi +@c man end + +@item --help +Display the command-line options supported by the program. + +@item --version +Display the version number of the program. + +@c man begin OPTIONS +@end table +@c man end + +@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.17/binutils/doc/config.texi b/contrib/binutils-2.17/binutils/doc/config.texi new file mode 100644 index 0000000000..c49c43a461 --- /dev/null +++ b/contrib/binutils-2.17/binutils/doc/config.texi @@ -0,0 +1,2 @@ +@set VERSION 2.17 +@set UPDATED June 2006 diff --git a/contrib/binutils-2.17/binutils/doc/fdl.texi b/contrib/binutils-2.17/binutils/doc/fdl.texi new file mode 100644 index 0000000000..cb9b4ae972 --- /dev/null +++ b/contrib/binutils-2.17/binutils/doc/fdl.texi @@ -0,0 +1,368 @@ +@c -*-texinfo-*- +@node GNU Free Documentation License + +@appendix GNU Free Documentation License +@center Version 1.1, March 2000 + +@display +Copyright (C) 2000, 2003 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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.17/binutils/doc/nm.1 b/contrib/binutils-2.17/binutils/doc/nm.1 new file mode 100644 index 0000000000..9f2271c7cb --- /dev/null +++ b/contrib/binutils-2.17/binutils/doc/nm.1 @@ -0,0 +1,449 @@ +.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 +.\" +.\" 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. \*(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- +.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 "2006-06-23" "binutils-2.17" "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\-\-special\-syms\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 symbol is determined in a system-specific manner without +error. On some systems, uppercase indicates that a default value has been +specified. +.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\-\-special\-syms\fR" 4 +.IX Item "--special-syms" +Display symbols which have a target-specific special meaning. These +symbols are usually used by the target for some special processing and +are not normally helpful when included included in the normal symbol +lists. For example for \s-1ARM\s0 targets this option would skip the mapping +symbols used to mark transistions between \s-1ARM\s0 code, \s-1THUMB\s0 code and +data. +.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. +.IP "\fB@\fR\fIfile\fR" 4 +.IX Item "@file" +Read command-line options from \fIfile\fR. The options read are +inserted in place of the original @\fIfile\fR option. If \fIfile\fR +does not exist, or cannot be read, then the option will be treated +literally, and not removed. +.Sp +Options in \fIfile\fR are separated by whitespace. A whitespace +character may be included in an option by surrounding the entire +option in either single or double quotes. Any character (including a +backslash) may be included by prefixing the character to be included +with a backslash. The \fIfile\fR may itself contain additional +@\fIfile\fR options; any such options will be processed recursively. +.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, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +2000, 2001, 2002, 2003, 2004, 2005, 2006 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 \*(L"\s-1GNU\s0 Free Documentation License\*(R". diff --git a/contrib/binutils-2.17/binutils/doc/objcopy.1 b/contrib/binutils-2.17/binutils/doc/objcopy.1 new file mode 100644 index 0000000000..828cddef56 --- /dev/null +++ b/contrib/binutils-2.17/binutils/doc/objcopy.1 @@ -0,0 +1,795 @@ +.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 +.\" +.\" 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. \*(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- +.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 "2006-06-23" "binutils-2.17" "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\-\-strip\-unneeded\-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\-\-globalize\-symbol=\fR\fIsymbolname\fR] + [\fB\-W\fR \fIsymbolname\fR|\fB\-\-weaken\-symbol=\fR\fIsymbolname\fR] + [\fB\-w\fR|\fB\-\-wildcard\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\-\-redefine\-syms=\fR\fIfilename\fR] + [\fB\-\-weaken\fR] + [\fB\-\-keep\-symbols=\fR\fIfilename\fR] + [\fB\-\-strip\-symbols=\fR\fIfilename\fR] + [\fB\-\-strip\-unneeded\-symbols=\fR\fIfilename\fR] + [\fB\-\-keep\-global\-symbols=\fR\fIfilename\fR] + [\fB\-\-localize\-symbols=\fR\fIfilename\fR] + [\fB\-\-globalize\-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\-\-add\-gnu\-debuglink=\fR\fIpath-to-file\fR] + [\fB\-\-keep\-file\-symbols\fR] + [\fB\-\-only\-keep\-debug\fR] + [\fB\-\-writable\-text\fR] + [\fB\-\-readonly\-text\fR] + [\fB\-\-pure\fR] + [\fB\-\-impure\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 or sections 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 +When stripping symbols, keep symbol \fIsymbolname\fR even if it would +normally be stripped. 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\-\-strip\-unneeded\-symbol=\fR\fIsymbolname\fR" 4 +.IX Item "--strip-unneeded-symbol=symbolname" +Do not copy symbol \fIsymbolname\fR from the source file unless it is needed +by a relocation. 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\-\-globalize\-symbol=\fR\fIsymbolname\fR" 4 +.IX Item "--globalize-symbol=symbolname" +Give symbol \fIsymbolname\fR global scoping so that it is visible +outside of the file in which it is defined. This option may be given +more than once. +.IP "\fB\-w\fR" 4 +.IX Item "-w" +.PD 0 +.IP "\fB\-\-wildcard\fR" 4 +.IX Item "--wildcard" +.PD +Permit regular expressions in \fIsymbolname\fRs used in other command +line options. The question mark (?), asterisk (*), backslash (\e) and +square brackets ([]) operators can be used anywhere in the symbol +name. If the first character of the symbol name is the exclamation +point (!) then the sense of the switch is reversed for that symbol. +For example: +.Sp +.Vb 1 +\& \-w \-W !foo \-W fo* +.Ve +.Sp +would cause objcopy to weaken all symbols that start with \*(L"fo\*(R" +except for the symbol \*(L"foo\*(R". +.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\-\-redefine\-syms=\fR\fIfilename\fR" 4 +.IX Item "--redefine-syms=filename" +Apply \fB\-\-redefine\-sym\fR to each symbol pair "\fIold\fR \fInew\fR" +listed in the file \fIfilename\fR. \fIfilename\fR is simply a flat file, +with one symbol pair per line. Line comments may be introduced by the hash +character. This option may be given more than once. +.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\-\-strip\-unneeded\-symbols=\fR\fIfilename\fR" 4 +.IX Item "--strip-unneeded-symbols=filename" +Apply \fB\-\-strip\-unneeded\-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\-\-globalize\-symbols=\fR\fIfilename\fR" 4 +.IX Item "--globalize-symbols=filename" +Apply \fB\-\-globalize\-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. For \s-1ELF\s0 based architectures if the \fIindex\fR +alternative does not exist then the value is treated as an absolute +number to be stored in the e_machine field of the \s-1ELF\s0 header. +.IP "\fB\-\-writable\-text\fR" 4 +.IX Item "--writable-text" +Mark the output text as writable. This option isn't meaningful for all +object file formats. +.IP "\fB\-\-readonly\-text\fR" 4 +.IX Item "--readonly-text" +Make the output text write protected. This option isn't meaningful for all +object file formats. +.IP "\fB\-\-pure\fR" 4 +.IX Item "--pure" +Mark the output file as demand paged. This option isn't meaningful for all +object file formats. +.IP "\fB\-\-impure\fR" 4 +.IX Item "--impure" +Mark the output file as impure. This option isn't meaningful for all +object file formats. +.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\-\-add\-gnu\-debuglink=\fR\fIpath-to-file\fR" 4 +.IX Item "--add-gnu-debuglink=path-to-file" +Creates a .gnu_debuglink section which contains a reference to \fIpath-to-file\fR +and adds it to the output file. +.IP "\fB\-\-keep\-file\-symbols\fR" 4 +.IX Item "--keep-file-symbols" +When stripping a file, perhaps with \fB\-\-strip\-debug\fR or +\&\fB\-\-strip\-unneeded\fR, retain any symbols specifying source file names, +which would otherwise get stripped. +.IP "\fB\-\-only\-keep\-debug\fR" 4 +.IX Item "--only-keep-debug" +Strip a file, removing contents of any sections that would not be +stripped by \fB\-\-strip\-debug\fR and leaving the debugging sections +intact. +.Sp +The intention is that this option will be used in conjunction with +\&\fB\-\-add\-gnu\-debuglink\fR to create a two part executable. One a +stripped binary which will occupy less space in \s-1RAM\s0 and in a +distribution and the second a debugging information file which is only +needed if debugging abilities are required. The suggested procedure +to create these files is as follows: +.RS 4 +.IP "1." 4 +.IX Item "1." +\&\f(CW\*(C`foo\*(C'\fR then... +.ie n .IP "1." 4 +.el .IP "1." 4 +.IX Item "1." +create a file containing the debugging info. +.ie n .IP "1." 4 +.el .IP "1." 4 +.IX Item "1." +stripped executable. +.ie n .IP "1." 4 +.el .IP "1." 4 +.IX Item "1." +to add a link to the debugging info into the stripped executable. +.RE +.RS 4 +.Sp +Note \- the choice of \f(CW\*(C`.dbg\*(C'\fR as an extension for the debug info +file is arbitrary. Also the \f(CW\*(C`\-\-only\-keep\-debug\*(C'\fR step is +optional. You could instead do this: +.IP "1." 4 +.IX Item "1." +.PD 0 +.ie n .IP "1." 4 +.el .IP "1." 4 +.IX Item "1." +.ie n .IP "1." 4 +.el .IP "1." 4 +.IX Item "1." +.ie n .IP "1." 4 +.el .IP "1." 4 +.IX Item "1." +.RE +.RS 4 +.PD +.Sp +i.e. the file pointed to by the \fB\-\-add\-gnu\-debuglink\fR can be the +full executable. It does not have to be a file created by the +\&\fB\-\-only\-keep\-debug\fR switch. +.RE +.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. +.IP "\fB@\fR\fIfile\fR" 4 +.IX Item "@file" +Read command-line options from \fIfile\fR. The options read are +inserted in place of the original @\fIfile\fR option. If \fIfile\fR +does not exist, or cannot be read, then the option will be treated +literally, and not removed. +.Sp +Options in \fIfile\fR are separated by whitespace. A whitespace +character may be included in an option by surrounding the entire +option in either single or double quotes. Any character (including a +backslash) may be included by prefixing the character to be included +with a backslash. The \fIfile\fR may itself contain additional +@\fIfile\fR options; any such options will be processed recursively. +.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, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +2000, 2001, 2002, 2003, 2004, 2005, 2006 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 \*(L"\s-1GNU\s0 Free Documentation License\*(R". diff --git a/contrib/binutils-2.17/binutils/doc/objdump.1 b/contrib/binutils-2.17/binutils/doc/objdump.1 new file mode 100644 index 0000000000..a27423c21b --- /dev/null +++ b/contrib/binutils-2.17/binutils/doc/objdump.1 @@ -0,0 +1,634 @@ +.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 +.\" +.\" 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. \*(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- +.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 "2006-06-23" "binutils-2.17" "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\-e\fR|\fB\-\-debugging\-tags\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\-W\fR|\fB\-\-dwarf\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\-\-special\-syms\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,\-e,\-f,\-g,\-G,\-h,\-H,\-p,\-r,\-R,\-s,\-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\-e\fR" 4 +.IX Item "-e" +.PD 0 +.IP "\fB\-\-debugging\-tags\fR" 4 +.IX Item "--debugging-tags" +.PD +Like \fB\-g\fR, but the information is generated in a format compatible +with ctags tool. +.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. If it is necessary to specify more than one +disassembler option then multiple \fB\-M\fR options can be used or +can be placed together into a comma separated list. +.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-names-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. \fBe300\fR selects +disassembly for the e300 family. +.Sp +For \s-1MIPS\s0, this option controls the printing of instruction mneumonic +names and 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 """no\-aliases""" 4 +.el .IP "\f(CWno\-aliases\fR" 4 +.IX Item "no-aliases" +Print the 'raw' instruction mneumonic instead of some pseudo +instruction mneumonic. I.E. print 'daddu' or 'or' instead of 'move', +\&'sll' instead of 'nop', etc. +.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. +.Sp +For \s-1VAX\s0, you can specify function entry addresses with \fB\-M +entry:0xf00ba\fR. You can use this multiple times to properly +disassemble \s-1VAX\s0 binary files that don't contain symbol tables (like +\&\s-1ROM\s0 dumps). In these cases, the function entry mask would otherwise +be decoded as \s-1VAX\s0 instructions, which would probably lead the the rest +of the function being wrongly disassembled. +.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. By default all +non-empty sections are displayed. +.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\-W\fR" 4 +.IX Item "-W" +.PD 0 +.IP "\fB\-\-dwarf\fR" 4 +.IX Item "--dwarf" +.PD +Displays the contents of the \s-1DWARF\s0 debug sections in the file, if any +are present. +.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\-\-special\-syms\fR" 4 +.IX Item "--special-syms" +When displaying symbols include those which the target considers to be +special in some way and which would not normally be of interest to the +user. +.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 \-p \-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. +.IP "\fB@\fR\fIfile\fR" 4 +.IX Item "@file" +Read command-line options from \fIfile\fR. The options read are +inserted in place of the original @\fIfile\fR option. If \fIfile\fR +does not exist, or cannot be read, then the option will be treated +literally, and not removed. +.Sp +Options in \fIfile\fR are separated by whitespace. A whitespace +character may be included in an option by surrounding the entire +option in either single or double quotes. Any character (including a +backslash) may be included by prefixing the character to be included +with a backslash. The \fIfile\fR may itself contain additional +@\fIfile\fR options; any such options will be processed recursively. +.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, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +2000, 2001, 2002, 2003, 2004, 2005, 2006 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 \*(L"\s-1GNU\s0 Free Documentation License\*(R". diff --git a/contrib/binutils-2.17/binutils/doc/ranlib.1 b/contrib/binutils-2.17/binutils/doc/ranlib.1 new file mode 100644 index 0000000000..fd03dd02c7 --- /dev/null +++ b/contrib/binutils-2.17/binutils/doc/ranlib.1 @@ -0,0 +1,188 @@ +.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 +.\" +.\" 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. \*(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- +.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 "2006-06-23" "binutils-2.17" "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. +.IP "\fB@\fR\fIfile\fR" 4 +.IX Item "@file" +Read command-line options from \fIfile\fR. The options read are +inserted in place of the original @\fIfile\fR option. If \fIfile\fR +does not exist, or cannot be read, then the option will be treated +literally, and not removed. +.Sp +Options in \fIfile\fR are separated by whitespace. A whitespace +character may be included in an option by surrounding the entire +option in either single or double quotes. Any character (including a +backslash) may be included by prefixing the character to be included +with a backslash. The \fIfile\fR may itself contain additional +@\fIfile\fR options; any such options will be processed recursively. +.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, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +2000, 2001, 2002, 2003, 2004, 2005, 2006 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 \*(L"\s-1GNU\s0 Free Documentation License\*(R". diff --git a/contrib/binutils-2.17/binutils/doc/readelf.1 b/contrib/binutils-2.17/binutils/doc/readelf.1 new file mode 100644 index 0000000000..14480c7938 --- /dev/null +++ b/contrib/binutils-2.17/binutils/doc/readelf.1 @@ -0,0 +1,376 @@ +.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 +.\" +.\" 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. \*(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- +.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 "2006-06-23" "binutils-2.17" "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\-g\fR|\fB\-\-section\-groups\fR] + [\fB\-t\fR|\fB\-\-section\-details\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[liaprmfFsoR]\fR| + \fB\-\-debug\-dump\fR[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames\-interp,=str,=loc,=Ranges]] + [\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. 32\-bit and +64\-bit \s-1ELF\s0 files are supported, as are archives containing \s-1ELF\s0 files. +.PP +This program performs a similar function to \fBobjdump\fR but it +goes into more detail and it exists independently of the \s-1BFD\s0 +library, so if there is a bug in \s-1BFD\s0 then readelf will not be +affected. +.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\-g\fR" 4 +.IX Item "-g" +.PD 0 +.IP "\fB\-\-section\-groups\fR" 4 +.IX Item "--section-groups" +.PD +Displays the information contained in the file's section groups, if it +has any. +.IP "\fB\-t\fR" 4 +.IX Item "-t" +.PD 0 +.IP "\fB\-\-section\-details\fR" 4 +.IX Item "--section-details" +.PD +Displays the detailed section information. Implies \fB\-S\fR. +.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 segments and/or sections, if any. +.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\-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. +A number identifies a particular section by index in the section table; +any other string identifies all sections with that name in the object file. +.IP "\fB\-w[liaprmfFsoR]\fR" 4 +.IX Item "-w[liaprmfFsoR]" +.PD 0 +.IP "\fB\-\-debug\-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames\-interp,=str,=loc,=Ranges]\fR" 4 +.IX Item "--debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges]" +.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. +.IP "\fB@\fR\fIfile\fR" 4 +.IX Item "@file" +Read command-line options from \fIfile\fR. The options read are +inserted in place of the original @\fIfile\fR option. If \fIfile\fR +does not exist, or cannot be read, then the option will be treated +literally, and not removed. +.Sp +Options in \fIfile\fR are separated by whitespace. A whitespace +character may be included in an option by surrounding the entire +option in either single or double quotes. Any character (including a +backslash) may be included by prefixing the character to be included +with a backslash. The \fIfile\fR may itself contain additional +@\fIfile\fR options; any such options will be processed recursively. +.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, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +2000, 2001, 2002, 2003, 2004, 2005, 2006 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 \*(L"\s-1GNU\s0 Free Documentation License\*(R". diff --git a/contrib/binutils-2.17/binutils/doc/size.1 b/contrib/binutils-2.17/binutils/doc/size.1 new file mode 100644 index 0000000000..1cf72ac7fe --- /dev/null +++ b/contrib/binutils-2.17/binutils/doc/size.1 @@ -0,0 +1,263 @@ +.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 +.\" +.\" 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. \*(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- +.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 "2006-06-23" "binutils-2.17" "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. +.IP "\fB@\fR\fIfile\fR" 4 +.IX Item "@file" +Read command-line options from \fIfile\fR. The options read are +inserted in place of the original @\fIfile\fR option. If \fIfile\fR +does not exist, or cannot be read, then the option will be treated +literally, and not removed. +.Sp +Options in \fIfile\fR are separated by whitespace. A whitespace +character may be included in an option by surrounding the entire +option in either single or double quotes. Any character (including a +backslash) may be included by prefixing the character to be included +with a backslash. The \fIfile\fR may itself contain additional +@\fIfile\fR options; any such options will be processed recursively. +.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, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +2000, 2001, 2002, 2003, 2004, 2005, 2006 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 \*(L"\s-1GNU\s0 Free Documentation License\*(R". diff --git a/contrib/binutils-2.17/binutils/doc/strings.1 b/contrib/binutils-2.17/binutils/doc/strings.1 new file mode 100644 index 0000000000..5cffee121b --- /dev/null +++ b/contrib/binutils-2.17/binutils/doc/strings.1 @@ -0,0 +1,249 @@ +.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 +.\" +.\" 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. \*(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- +.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 "2006-06-23" "binutils-2.17" "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. +.IP "\fB@\fR\fIfile\fR" 4 +.IX Item "@file" +Read command-line options from \fIfile\fR. The options read are +inserted in place of the original @\fIfile\fR option. If \fIfile\fR +does not exist, or cannot be read, then the option will be treated +literally, and not removed. +.Sp +Options in \fIfile\fR are separated by whitespace. A whitespace +character may be included in an option by surrounding the entire +option in either single or double quotes. Any character (including a +backslash) may be included by prefixing the character to be included +with a backslash. The \fIfile\fR may itself contain additional +@\fIfile\fR options; any such options will be processed recursively. +.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, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +2000, 2001, 2002, 2003, 2004, 2005, 2006 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 \*(L"\s-1GNU\s0 Free Documentation License\*(R". diff --git a/contrib/binutils-2.17/binutils/doc/strip.1 b/contrib/binutils-2.17/binutils/doc/strip.1 new file mode 100644 index 0000000000..982255ef75 --- /dev/null +++ b/contrib/binutils-2.17/binutils/doc/strip.1 @@ -0,0 +1,383 @@ +.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 +.\" +.\" 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. \*(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- +.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 "2006-06-23" "binutils-2.17" "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\-w\fR|\fB\-\-wildcard\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\-\-keep\-file\-symbols\fR] + [\fB\-\-only\-keep\-debug\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 +When stripping symbols, keep symbol \fIsymbolname\fR even if it would +normally be stripped. 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\-w\fR" 4 +.IX Item "-w" +.PD 0 +.IP "\fB\-\-wildcard\fR" 4 +.IX Item "--wildcard" +.PD +Permit regular expressions in \fIsymbolname\fRs used in other command +line options. The question mark (?), asterisk (*), backslash (\e) and +square brackets ([]) operators can be used anywhere in the symbol +name. If the first character of the symbol name is the exclamation +point (!) then the sense of the switch is reversed for that symbol. +For example: +.Sp +.Vb 1 +\& \-w \-K !foo \-K fo* +.Ve +.Sp +would cause strip to only keep symbols that start with the letters +\&\*(L"fo\*(R", but to discard the symbol \*(L"foo\*(R". +.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\-\-keep\-file\-symbols\fR" 4 +.IX Item "--keep-file-symbols" +When stripping a file, perhaps with \fB\-\-strip\-debug\fR or +\&\fB\-\-strip\-unneeded\fR, retain any symbols specifying source file names, +which would otherwise get stripped. +.IP "\fB\-\-only\-keep\-debug\fR" 4 +.IX Item "--only-keep-debug" +Strip a file, removing any sections that would be stripped by +\&\fB\-\-strip\-debug\fR and leaving the debugging sections. +.Sp +The intention is that this option will be used in conjunction with +\&\fB\-\-add\-gnu\-debuglink\fR to create a two part executable. One a +stripped binary which will occupy less space in \s-1RAM\s0 and in a +distribution and the second a debugging information file which is only +needed if debugging abilities are required. The suggested procedure +to create these files is as follows: +.RS 4 +.IP "1." 4 +.IX Item "1." +\&\f(CW\*(C`foo\*(C'\fR then... +.ie n .IP "1." 4 +.el .IP "1." 4 +.IX Item "1." +create a file containing the debugging info. +.ie n .IP "1." 4 +.el .IP "1." 4 +.IX Item "1." +stripped executable. +.ie n .IP "1." 4 +.el .IP "1." 4 +.IX Item "1." +to add a link to the debugging info into the stripped executable. +.RE +.RS 4 +.Sp +Note \- the choice of \f(CW\*(C`.dbg\*(C'\fR as an extension for the debug info +file is arbitrary. Also the \f(CW\*(C`\-\-only\-keep\-debug\*(C'\fR step is +optional. You could instead do this: +.IP "1." 4 +.IX Item "1." +.PD 0 +.ie n .IP "1." 4 +.el .IP "1." 4 +.IX Item "1." +.ie n .IP "1." 4 +.el .IP "1." 4 +.IX Item "1." +.ie n .IP "1." 4 +.el .IP "1." 4 +.IX Item "1." +.RE +.RS 4 +.PD +.Sp +ie the file pointed to by the \fB\-\-add\-gnu\-debuglink\fR can be the +full executable. It does not have to be a file created by the +\&\fB\-\-only\-keep\-debug\fR switch. +.RE +.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. +.IP "\fB@\fR\fIfile\fR" 4 +.IX Item "@file" +Read command-line options from \fIfile\fR. The options read are +inserted in place of the original @\fIfile\fR option. If \fIfile\fR +does not exist, or cannot be read, then the option will be treated +literally, and not removed. +.Sp +Options in \fIfile\fR are separated by whitespace. A whitespace +character may be included in an option by surrounding the entire +option in either single or double quotes. Any character (including a +backslash) may be included by prefixing the character to be included +with a backslash. The \fIfile\fR may itself contain additional +@\fIfile\fR options; any such options will be processed recursively. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +the Info entries for \fIbinutils\fR. +.SH "COPYRIGHT" +.IX Header "COPYRIGHT" +Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +2000, 2001, 2002, 2003, 2004, 2005, 2006 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 \*(L"\s-1GNU\s0 Free Documentation License\*(R". diff --git a/contrib/binutils-2.17/binutils/dwarf.c b/contrib/binutils-2.17/binutils/dwarf.c new file mode 100644 index 0000000000..c69cab224b --- /dev/null +++ b/contrib/binutils-2.17/binutils/dwarf.c @@ -0,0 +1,3732 @@ +/* dwarf.c -- display DWARF contents of a BFD binary file + Copyright 2005, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#include + +#include "dwarf.h" + +#include "bucomm.h" +#include "libiberty.h" + +static int have_frame_base; +static int need_base_address; + +static unsigned int last_pointer_size = 0; +static int warned_about_missing_comp_units = FALSE; + +static unsigned int num_debug_info_entries = 0; +static debug_info *debug_information = NULL; + +dwarf_vma eh_addr_size; +int is_relocatable; + +int do_debug_info; +int do_debug_abbrevs; +int do_debug_lines; +int do_debug_pubnames; +int do_debug_aranges; +int do_debug_ranges; +int do_debug_frames; +int do_debug_frames_interp; +int do_debug_macinfo; +int do_debug_str; +int do_debug_loc; + +dwarf_vma (*byte_get) (unsigned char *, int); + +dwarf_vma +byte_get_little_endian (unsigned char *field, int size) +{ + switch (size) + { + case 1: + return *field; + + case 2: + return ((unsigned int) (field[0])) + | (((unsigned int) (field[1])) << 8); + + case 4: + return ((unsigned long) (field[0])) + | (((unsigned long) (field[1])) << 8) + | (((unsigned long) (field[2])) << 16) + | (((unsigned long) (field[3])) << 24); + + case 8: + if (sizeof (dwarf_vma) == 8) + return ((dwarf_vma) (field[0])) + | (((dwarf_vma) (field[1])) << 8) + | (((dwarf_vma) (field[2])) << 16) + | (((dwarf_vma) (field[3])) << 24) + | (((dwarf_vma) (field[4])) << 32) + | (((dwarf_vma) (field[5])) << 40) + | (((dwarf_vma) (field[6])) << 48) + | (((dwarf_vma) (field[7])) << 56); + else if (sizeof (dwarf_vma) == 4) + /* 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. */ + return ((unsigned long) (field[0])) + | (((unsigned long) (field[1])) << 8) + | (((unsigned long) (field[2])) << 16) + | (((unsigned long) (field[3])) << 24); + + default: + error (_("Unhandled data length: %d\n"), size); + abort (); + } +} + +dwarf_vma +byte_get_big_endian (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); + + case 8: + if (sizeof (dwarf_vma) == 8) + return ((dwarf_vma) (field[7])) + | (((dwarf_vma) (field[6])) << 8) + | (((dwarf_vma) (field[5])) << 16) + | (((dwarf_vma) (field[4])) << 24) + | (((dwarf_vma) (field[3])) << 32) + | (((dwarf_vma) (field[2])) << 40) + | (((dwarf_vma) (field[1])) << 48) + | (((dwarf_vma) (field[0])) << 56); + else if (sizeof (dwarf_vma) == 4) + { + /* Although we are extracing data from an 8 byte wide field, + we are returning only 4 bytes of data. */ + field += 4; + return ((unsigned long) (field[3])) + | (((unsigned long) (field[2])) << 8) + | (((unsigned long) (field[1])) << 16) + | (((unsigned long) (field[0])) << 24); + } + + default: + error (_("Unhandled data length: %d\n"), size); + abort (); + } +} + +static dwarf_vma +byte_get_signed (unsigned char *field, int size) +{ + dwarf_vma x = byte_get (field, size); + + switch (size) + { + case 1: + return (x ^ 0x80) - 0x80; + case 2: + return (x ^ 0x8000) - 0x8000; + case 4: + return (x ^ 0x80000000) - 0x80000000; + case 8: + return x; + default: + abort (); + } +} + +static unsigned long int +read_leb128 (unsigned char *data, unsigned int *length_return, int sign) +{ + unsigned long int result = 0; + unsigned int num_read = 0; + unsigned int shift = 0; + unsigned char byte; + + do + { + byte = *data++; + num_read++; + + result |= ((unsigned long int) (byte & 0x7f)) << shift; + + shift += 7; + + } + while (byte & 0x80); + + if (length_return != NULL) + *length_return = num_read; + + if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40)) + result |= -1L << 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 (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 the number of bytes read. */ + +static int +process_extended_line_op (unsigned char *data, int is_stmt) +{ + unsigned char op_code; + unsigned 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, len - bytes_read - 1); + 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; +} + +static const char * +fetch_indirect_string (unsigned long offset) +{ + struct dwarf_section *section = &debug_displays [str].section; + + if (section->start == NULL) + return _(""); + + /* DWARF sections under Mach-O have non-zero addresses. */ + offset -= section->address; + if (offset > section->size) + { + warn (_("DW_FORM_strp offset too big: %lx\n"), offset); + return _(""); + } + + return (const char *) section->start + offset; +} + +/* FIXME: There are better and more efficient 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 (void) +{ + 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 (unsigned long number, unsigned long tag, int children) +{ + abbrev_entry *entry; + + 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 (unsigned long attribute, unsigned long form) +{ + abbrev_attr *attr; + + 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 (unsigned char *start, unsigned char *end) +{ + if (first_abbrev != NULL) + return NULL; + + while (start < end) + { + unsigned 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 char * +get_TAG_name (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]; + + snprintf (buffer, sizeof (buffer), _("Unknown TAG value: %lx"), tag); + return buffer; + } + } +} + +static char * +get_FORM_name (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]; + + snprintf (buffer, sizeof (buffer), _("Unknown FORM value: %lx"), form); + return buffer; + } + } +} + +static unsigned char * +display_block (unsigned char *data, unsigned long length) +{ + printf (_(" %lu byte block: "), length); + + while (length --) + printf ("%lx ", (unsigned long) byte_get (data++, 1)); + + return data; +} + +static int +decode_location_expression (unsigned char * data, + unsigned int pointer_size, + unsigned long length, + unsigned long cu_offset) +{ + unsigned op; + unsigned int bytes_read; + unsigned long uvalue; + unsigned char *end = data + length; + int need_frame_base = 0; + + 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_signed (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_signed (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_signed (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_signed (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_signed (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: + need_frame_base = 1; + 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: + /* XXX: Strictly speaking for 64-bit DWARF3 files + this ought to be an 8-byte wide computation. */ + printf ("DW_OP_call2: <%lx>", (long) byte_get (data, 2) + cu_offset); + data += 2; + break; + case DW_OP_call4: + /* XXX: Strictly speaking for 64-bit DWARF3 files + this ought to be an 8-byte wide computation. */ + printf ("DW_OP_call4: <%lx>", (long) byte_get (data, 4) + cu_offset); + 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 need_frame_base; + } + + /* Separate the ops. */ + if (data < end) + printf ("; "); + } + + return need_frame_base; +} + +static unsigned char * +read_and_display_attr_value (unsigned long attribute, + unsigned long form, + unsigned char *data, + unsigned long cu_offset, + unsigned long pointer_size, + unsigned long offset_size, + int dwarf_version, + debug_info *debug_info_p, + int do_loc) +{ + unsigned long uvalue = 0; + unsigned char *block_start = NULL; + unsigned 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; + if (!do_loc) + printf (" %s", get_FORM_name (form)); + return read_and_display_attr_value (attribute, form, data, + cu_offset, pointer_size, + offset_size, dwarf_version, + debug_info_p, do_loc); + } + + switch (form) + { + case DW_FORM_ref_addr: + if (!do_loc) + printf (" <#%lx>", uvalue); + break; + + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref_udata: + if (!do_loc) + printf (" <%lx>", uvalue + cu_offset); + break; + + case DW_FORM_data4: + case DW_FORM_addr: + if (!do_loc) + printf (" %#lx", uvalue); + break; + + case DW_FORM_flag: + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_sdata: + case DW_FORM_udata: + if (!do_loc) + printf (" %ld", uvalue); + break; + + case DW_FORM_ref8: + case DW_FORM_data8: + if (!do_loc) + { + uvalue = byte_get (data, 4); + printf (" %lx", uvalue); + printf (" %lx", (unsigned long) byte_get (data + 4, 4)); + } + if ((do_loc || do_debug_loc || do_debug_ranges) + && num_debug_info_entries == 0) + { + if (sizeof (uvalue) == 8) + uvalue = byte_get (data, 8); + else + error (_("DW_FORM_data8 is unsupported when sizeof (unsigned long) != 8\n")); + } + data += 8; + break; + + case DW_FORM_string: + if (!do_loc) + 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; + if (do_loc) + data = block_start + uvalue; + else + data = display_block (block_start, uvalue); + break; + + case DW_FORM_block1: + uvalue = byte_get (data, 1); + block_start = data + 1; + if (do_loc) + data = block_start + uvalue; + else + data = display_block (block_start, uvalue); + break; + + case DW_FORM_block2: + uvalue = byte_get (data, 2); + block_start = data + 2; + if (do_loc) + data = block_start + uvalue; + else + data = display_block (block_start, uvalue); + break; + + case DW_FORM_block4: + uvalue = byte_get (data, 4); + block_start = data + 4; + if (do_loc) + data = block_start + uvalue; + else + data = display_block (block_start, uvalue); + break; + + case DW_FORM_strp: + if (!do_loc) + printf (_(" (indirect string, offset: 0x%lx): %s"), + uvalue, fetch_indirect_string (uvalue)); + break; + + case DW_FORM_indirect: + /* Handled above. */ + break; + + default: + warn (_("Unrecognized form: %lu\n"), form); + break; + } + + /* For some attributes we can display further information. */ + if ((do_loc || do_debug_loc || do_debug_ranges) + && num_debug_info_entries == 0) + { + switch (attribute) + { + case DW_AT_frame_base: + have_frame_base = 1; + 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 (form == DW_FORM_data4 || form == DW_FORM_data8) + { + /* Process location list. */ + unsigned int max = debug_info_p->max_loc_offsets; + unsigned int num = debug_info_p->num_loc_offsets; + + if (max == 0 || num >= max) + { + max += 1024; + debug_info_p->loc_offsets + = xcrealloc (debug_info_p->loc_offsets, + max, sizeof (*debug_info_p->loc_offsets)); + debug_info_p->have_frame_base + = xcrealloc (debug_info_p->have_frame_base, + max, sizeof (*debug_info_p->have_frame_base)); + debug_info_p->max_loc_offsets = max; + } + debug_info_p->loc_offsets [num] = uvalue; + debug_info_p->have_frame_base [num] = have_frame_base; + debug_info_p->num_loc_offsets++; + } + break; + + case DW_AT_low_pc: + if (need_base_address) + debug_info_p->base_address = uvalue; + break; + + case DW_AT_ranges: + if (form == DW_FORM_data4 || form == DW_FORM_data8) + { + /* Process range list. */ + unsigned int max = debug_info_p->max_range_lists; + unsigned int num = debug_info_p->num_range_lists; + + if (max == 0 || num >= max) + { + max += 1024; + debug_info_p->range_lists + = xcrealloc (debug_info_p->range_lists, + max, sizeof (*debug_info_p->range_lists)); + debug_info_p->max_range_lists = max; + } + debug_info_p->range_lists [num] = uvalue; + debug_info_p->num_range_lists++; + } + break; + + default: + break; + } + } + + if (do_loc) + return data; + + 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; + case DW_ATE_decimal_float: printf ("(decimal 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: + have_frame_base = 1; + 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) + { + int need_frame_base; + + printf ("("); + need_frame_base = decode_location_expression (block_start, + pointer_size, + uvalue, + cu_offset); + printf (")"); + if (need_frame_base && !have_frame_base) + printf (_(" [without DW_AT_frame_base]")); + } + else if (form == DW_FORM_data4 || form == DW_FORM_data8) + printf (_("(location list)")); + + break; + + default: + break; + } + + return data; +} + +static char * +get_AT_name (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]; + + snprintf (buffer, sizeof (buffer), _("Unknown AT value: %lx"), + attribute); + return buffer; + } + } +} + +static unsigned char * +read_and_display_attr (unsigned long attribute, + unsigned long form, + unsigned char *data, + unsigned long cu_offset, + unsigned long pointer_size, + unsigned long offset_size, + int dwarf_version, + debug_info *debug_info_p, + int do_loc) +{ + if (!do_loc) + printf (" %-18s:", get_AT_name (attribute)); + data = read_and_display_attr_value (attribute, form, data, cu_offset, + pointer_size, offset_size, + dwarf_version, debug_info_p, + do_loc); + if (!do_loc) + printf ("\n"); + return data; +} + + +/* Process the contents of a .debug_info section. If do_loc is non-zero + then we are scanning for location lists and we do not want to display + anything to the user. */ + +static int +process_debug_info (struct dwarf_section *section, void *file, + int do_loc) +{ + unsigned char *start = section->start; + unsigned char *end = start + section->size; + unsigned char *section_begin; + unsigned int unit; + unsigned int num_units = 0; + + if ((do_loc || do_debug_loc || do_debug_ranges) + && num_debug_info_entries == 0) + { + unsigned long length; + + /* First scan the section to get the number of comp units. */ + for (section_begin = start, num_units = 0; section_begin < end; + num_units ++) + { + /* 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. */ + length = byte_get (section_begin, 4); + + if (length == 0xffffffff) + { + length = byte_get (section_begin + 4, 8); + section_begin += length + 12; + } + else + section_begin += length + 4; + } + + if (num_units == 0) + { + error (_("No comp units in %s section ?"), section->name); + return 0; + } + + /* Then allocate an array to hold the information. */ + debug_information = cmalloc (num_units, + sizeof (* debug_information)); + if (debug_information == NULL) + { + error (_("Not enough memory for a debug info array of %u entries"), + num_units); + return 0; + } + } + + if (!do_loc) + { + printf (_("The section %s contains:\n\n"), section->name); + + load_debug_section (str, file); + } + + load_debug_section (abbrev, file); + if (debug_displays [abbrev].section.start == NULL) + { + warn (_("Unable to locate %s section!\n"), + debug_displays [abbrev].section.name); + return 0; + } + + for (section_begin = start, unit = 0; start < end; unit++) + { + DWARF2_Internal_CompUnit compunit; + unsigned char *hdrptr; + unsigned char *cu_abbrev_offset_ptr; + unsigned char *tags; + 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; + + cu_offset = start - section_begin; + start += compunit.cu_length + initial_length_size; + + 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; + if ((do_loc || do_debug_loc || do_debug_ranges) + && num_debug_info_entries == 0) + { + debug_information [unit].cu_offset = cu_offset; + debug_information [unit].pointer_size + = compunit.cu_pointer_size; + debug_information [unit].base_address = 0; + debug_information [unit].loc_offsets = NULL; + debug_information [unit].have_frame_base = NULL; + debug_information [unit].max_loc_offsets = 0; + debug_information [unit].num_loc_offsets = 0; + debug_information [unit].range_lists = NULL; + debug_information [unit].max_range_lists= 0; + debug_information [unit].num_range_lists = 0; + } + + tags = hdrptr; + + if (!do_loc) + { + printf (_(" Compilation Unit @ offset 0x%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 (); + + /* Process the abbrevs used by this compilation unit. DWARF + sections under Mach-O have non-zero addresses. */ + process_abbrev_section + ((unsigned char *) debug_displays [abbrev].section.start + + compunit.cu_abbrev_offset - debug_displays [abbrev].section.address, + (unsigned char *) debug_displays [abbrev].section.start + + debug_displays [abbrev].section.size); + + level = 0; + while (tags < start) + { + unsigned 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; + } + + if (!do_loc) + printf (_(" <%d><%lx>: Abbrev Number: %lu (%s)\n"), + level, + (unsigned long) (tags - section_begin + - bytes_read), + abbrev_number, + get_TAG_name (entry->tag)); + + switch (entry->tag) + { + default: + need_base_address = 0; + break; + case DW_TAG_compile_unit: + need_base_address = 1; + break; + case DW_TAG_entry_point: + case DW_TAG_inlined_subroutine: + case DW_TAG_subprogram: + need_base_address = 0; + /* Assuming that there is no DW_AT_frame_base. */ + have_frame_base = 0; + break; + } + + 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, + &debug_information [unit], + do_loc); + + if (entry->children) + ++level; + } + } + + /* Set num_debug_info_entries here so that it can be used to check if + we need to process .debug_loc and .debug_ranges sections. */ + if ((do_loc || do_debug_loc || do_debug_ranges) + && num_debug_info_entries == 0) + num_debug_info_entries = num_units; + + if (!do_loc) + { + printf ("\n"); + } + + return 1; +} + +/* Locate and scan the .debug_info section in the file and record the pointer + sizes and offsets for the compilation units in it. Usually an executable + will have just one pointer size, but this is not guaranteed, and so we try + not to make any assumptions. Returns zero upon failure, or the number of + compilation units upon success. */ + +static unsigned int +load_debug_info (void * file) +{ + /* Reset the last pointer size so that we can issue correct error + messages if we are displaying the contents of more than one section. */ + last_pointer_size = 0; + warned_about_missing_comp_units = FALSE; + + /* If we already have the information there is nothing else to do. */ + if (num_debug_info_entries > 0) + return num_debug_info_entries; + + if (load_debug_section (info, file) + && process_debug_info (&debug_displays [info].section, file, 1)) + return num_debug_info_entries; + else + return 0; +} + +static int +display_debug_lines (struct dwarf_section *section, void *file) +{ + unsigned char *start = section->start; + unsigned char *data = start; + unsigned char *end = start + section->size; + + printf (_("\nDump of debug contents of section %s:\n\n"), + section->name); + + load_debug_info (file); + + while (data < end) + { + DWARF2_Internal_LineInfo info; + unsigned char *standard_opcodes; + unsigned char *end_of_sequence; + unsigned char *hdrptr; + int initial_length_size; + int offset_size; + int i; + + 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->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; + unsigned 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; + unsigned long int uladv; + unsigned int bytes_read; + + op_code = *data++; + + if (op_code >= info.li_opcode_base) + { + op_code -= info.li_opcode_base; + uladv = (op_code / info.li_line_range) * info.li_min_insn_length; + state_machine_regs.address += uladv; + printf (_(" Special opcode %d: advance Address by %lu to 0x%lx"), + op_code, uladv, 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); + break; + + case DW_LNS_copy: + printf (_(" Copy\n")); + break; + + case DW_LNS_advance_pc: + uladv = read_leb128 (data, & bytes_read, 0); + uladv *= info.li_min_insn_length; + data += bytes_read; + state_machine_regs.address += uladv; + printf (_(" Advance PC by %lu to 0x%lx\n"), uladv, + 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: + uladv = read_leb128 (data, & bytes_read, 0); + data += bytes_read; + printf (_(" Set column to %lu\n"), uladv); + state_machine_regs.column = uladv; + 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: + uladv = (((255 - info.li_opcode_base) / info.li_line_range) + * info.li_min_insn_length); + state_machine_regs.address += uladv; + printf (_(" Advance PC by constant %lu to 0x%lx\n"), uladv, + state_machine_regs.address); + break; + + case DW_LNS_fixed_advance_pc: + uladv = byte_get (data, 2); + data += 2; + state_machine_regs.address += uladv; + printf (_(" Advance PC by fixed size amount %lu to 0x%lx\n"), + uladv, 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: + uladv = read_leb128 (data, & bytes_read, 0); + data += bytes_read; + printf (_(" Set ISA to %lu\n"), uladv); + break; + + default: + printf (_(" Unknown opcode %d with operands: "), op_code); + + 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 (struct dwarf_section *section, + void *file ATTRIBUTE_UNUSED) +{ + DWARF2_Internal_PubNames pubnames; + unsigned char *start = section->start; + unsigned char *end = start + section->size; + + printf (_("Contents of the %s section:\n\n"), section->name); + + 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 (" %-6ld\t\t%s\n", offset, data); + data += strlen ((char *) data) + 1; + } + } + while (offset != 0); + } + + printf ("\n"); + return 1; +} + +static int +display_debug_macinfo (struct dwarf_section *section, + void *file ATTRIBUTE_UNUSED) +{ + unsigned char *start = section->start; + unsigned char *end = start + section->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); + + 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 = (char *) 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 = (char *) 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 = (char *) 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 (struct dwarf_section *section, + void *file ATTRIBUTE_UNUSED) +{ + abbrev_entry *entry; + unsigned char *start = section->start; + unsigned char *end = start + section->size; + + printf (_("Contents of the %s section:\n\n"), section->name); + + do + { + free_abbrevs (); + + 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)); + } + } + while (start); + + printf ("\n"); + + return 1; +} + +static int +display_debug_loc (struct dwarf_section *section, void *file) +{ + unsigned char *start = section->start; + unsigned char *section_end; + unsigned long bytes; + unsigned char *section_begin = start; + unsigned int num_loc_list = 0; + unsigned long last_offset = 0; + unsigned int first = 0; + unsigned int i; + unsigned int j; + int seen_first_offset = 0; + int use_debug_info = 1; + unsigned char *next; + + bytes = section->size; + section_end = start + bytes; + + if (bytes == 0) + { + printf (_("\nThe %s section is empty.\n"), section->name); + return 0; + } + + load_debug_info (file); + + /* Check the order of location list in .debug_info section. If + offsets of location lists are in the ascending order, we can + use `debug_information' directly. */ + for (i = 0; i < num_debug_info_entries; i++) + { + unsigned int num; + + num = debug_information [i].num_loc_offsets; + num_loc_list += num; + + /* Check if we can use `debug_information' directly. */ + if (use_debug_info && num != 0) + { + if (!seen_first_offset) + { + /* This is the first location list. */ + last_offset = debug_information [i].loc_offsets [0]; + first = i; + seen_first_offset = 1; + j = 1; + } + else + j = 0; + + for (; j < num; j++) + { + if (last_offset > + debug_information [i].loc_offsets [j]) + { + use_debug_info = 0; + break; + } + last_offset = debug_information [i].loc_offsets [j]; + } + } + } + + if (!use_debug_info) + /* FIXME: Should we handle this case? */ + error (_("Location lists in .debug_info section aren't in ascending order!\n")); + + if (!seen_first_offset) + error (_("No location lists in .debug_info section!\n")); + + /* DWARF sections under Mach-O have non-zero addresses. */ + if (debug_information [first].loc_offsets [0] != section->address) + warn (_("Location lists in %s section start at 0x%lx\n"), + section->name, debug_information [first].loc_offsets [0]); + + printf (_("Contents of the %s section:\n\n"), section->name); + printf (_(" Offset Begin End Expression\n")); + + seen_first_offset = 0; + for (i = first; i < num_debug_info_entries; i++) + { + unsigned long begin; + unsigned long end; + unsigned short length; + unsigned long offset; + unsigned int pointer_size; + unsigned long cu_offset; + unsigned long base_address; + int need_frame_base; + int has_frame_base; + + pointer_size = debug_information [i].pointer_size; + cu_offset = debug_information [i].cu_offset; + + for (j = 0; j < debug_information [i].num_loc_offsets; j++) + { + has_frame_base = debug_information [i].have_frame_base [j]; + /* DWARF sections under Mach-O have non-zero addresses. */ + offset = debug_information [i].loc_offsets [j] - section->address; + next = section_begin + offset; + base_address = debug_information [i].base_address; + + if (!seen_first_offset) + seen_first_offset = 1; + else + { + if (start < next) + warn (_("There is a hole [0x%lx - 0x%lx] in .debug_loc section.\n"), + (long)(start - section_begin), (long)(next - section_begin)); + else if (start > next) + warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_loc section.\n"), + (long)(start - section_begin), (long)(next - section_begin)); + } + start = next; + + if (offset >= bytes) + { + warn (_("Offset 0x%lx is bigger than .debug_loc section size.\n"), + offset); + continue; + } + + while (1) + { + if (start + 2 * pointer_size > section_end) + { + warn (_("Location list starting at offset 0x%lx is not terminated.\n"), + offset); + break; + } + + begin = byte_get (start, pointer_size); + start += pointer_size; + end = byte_get (start, pointer_size); + start += pointer_size; + + if (begin == 0 && end == 0) + { + printf (_(" %8.8lx \n"), offset); + break; + } + + /* Check base address specifiers. */ + if (begin == -1UL && end != -1UL) + { + base_address = end; + printf (_(" %8.8lx %8.8lx %8.8lx (base address)\n"), + offset, begin, end); + continue; + } + + if (start + 2 > section_end) + { + warn (_("Location list starting at offset 0x%lx is not terminated.\n"), + offset); + break; + } + + length = byte_get (start, 2); + start += 2; + + if (start + length > section_end) + { + warn (_("Location list starting at offset 0x%lx is not terminated.\n"), + offset); + break; + } + + printf (" %8.8lx %8.8lx %8.8lx (", + offset, begin + base_address, end + base_address); + need_frame_base = decode_location_expression (start, + pointer_size, + length, + cu_offset); + putchar (')'); + + if (need_frame_base && !has_frame_base) + printf (_(" [without DW_AT_frame_base]")); + + if (begin == end) + fputs (_(" (start == end)"), stdout); + else if (begin > end) + fputs (_(" (start > end)"), stdout); + + putchar ('\n'); + + start += length; + } + } + } + return 1; +} + +static int +display_debug_str (struct dwarf_section *section, + void *file ATTRIBUTE_UNUSED) +{ + unsigned char *start = section->start; + unsigned long bytes = section->size; + dwarf_vma addr = section->address; + + if (bytes == 0) + { + printf (_("\nThe %s section is empty.\n"), section->name); + return 0; + } + + printf (_("Contents of the %s section:\n\n"), section->name); + + 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; + } + + putchar ('\n'); + + return 1; +} + + +static int +display_debug_info (struct dwarf_section *section, void *file) +{ + return process_debug_info (section, file, 0); +} + + +static int +display_debug_aranges (struct dwarf_section *section, + void *file ATTRIBUTE_UNUSED) +{ + unsigned char *start = section->start; + unsigned char *end = start + section->size; + + printf (_("The section %s contains:\n\n"), section->name); + + 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; + + start += arange.ar_length + initial_length_size; + + while (ranges + 2 * arange.ar_pointer_size <= start) + { + 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; + + printf (" %8.8lx %lu\n", address, length); + } + } + + printf ("\n"); + + return 1; +} + +static int +display_debug_ranges (struct dwarf_section *section, + void *file ATTRIBUTE_UNUSED) +{ + unsigned char *start = section->start; + unsigned char *section_end; + unsigned long bytes; + unsigned char *section_begin = start; + unsigned int num_range_list = 0; + unsigned long last_offset = 0; + unsigned int first = 0; + unsigned int i; + unsigned int j; + int seen_first_offset = 0; + int use_debug_info = 1; + unsigned char *next; + + bytes = section->size; + section_end = start + bytes; + + if (bytes == 0) + { + printf (_("\nThe %s section is empty.\n"), section->name); + return 0; + } + + load_debug_info (file); + + /* Check the order of range list in .debug_info section. If + offsets of range lists are in the ascending order, we can + use `debug_information' directly. */ + for (i = 0; i < num_debug_info_entries; i++) + { + unsigned int num; + + num = debug_information [i].num_range_lists; + num_range_list += num; + + /* Check if we can use `debug_information' directly. */ + if (use_debug_info && num != 0) + { + if (!seen_first_offset) + { + /* This is the first range list. */ + last_offset = debug_information [i].range_lists [0]; + first = i; + seen_first_offset = 1; + j = 1; + } + else + j = 0; + + for (; j < num; j++) + { + if (last_offset > + debug_information [i].range_lists [j]) + { + use_debug_info = 0; + break; + } + last_offset = debug_information [i].range_lists [j]; + } + } + } + + if (!use_debug_info) + /* FIXME: Should we handle this case? */ + error (_("Range lists in .debug_info section aren't in ascending order!\n")); + + if (!seen_first_offset) + error (_("No range lists in .debug_info section!\n")); + + /* DWARF sections under Mach-O have non-zero addresses. */ + if (debug_information [first].range_lists [0] != section->address) + warn (_("Range lists in %s section start at 0x%lx\n"), + section->name, debug_information [first].range_lists [0]); + + printf (_("Contents of the %s section:\n\n"), section->name); + printf (_(" Offset Begin End\n")); + + seen_first_offset = 0; + for (i = first; i < num_debug_info_entries; i++) + { + unsigned long begin; + unsigned long end; + unsigned long offset; + unsigned int pointer_size; + unsigned long base_address; + + pointer_size = debug_information [i].pointer_size; + + for (j = 0; j < debug_information [i].num_range_lists; j++) + { + /* DWARF sections under Mach-O have non-zero addresses. */ + offset = debug_information [i].range_lists [j] - section->address; + next = section_begin + offset; + base_address = debug_information [i].base_address; + + if (!seen_first_offset) + seen_first_offset = 1; + else + { + if (start < next) + warn (_("There is a hole [0x%lx - 0x%lx] in %s section.\n"), + (long)(start - section_begin), + (long)(next - section_begin), section->name); + else if (start > next) + warn (_("There is an overlap [0x%lx - 0x%lx] in %s section.\n"), + (long)(start - section_begin), + (long)(next - section_begin), section->name); + } + start = next; + + while (1) + { + begin = byte_get (start, pointer_size); + start += pointer_size; + end = byte_get (start, pointer_size); + start += pointer_size; + + if (begin == 0 && end == 0) + { + printf (_(" %8.8lx \n"), offset); + break; + } + + /* Check base address specifiers. */ + if (begin == -1UL && end != -1UL) + { + base_address = end; + printf (" %8.8lx %8.8lx %8.8lx (base address)\n", + offset, begin, end); + continue; + } + + printf (" %8.8lx %8.8lx %8.8lx", + offset, begin + base_address, end + base_address); + + if (begin == end) + fputs (_(" (start == end)"), stdout); + else if (begin > end) + fputs (_(" (start > end)"), stdout); + + putchar ('\n'); + } + } + } + putchar ('\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 (Frame_Chunk *fc, int reg) +{ + int prev = fc->ncols; + + if (reg < fc->ncols) + return; + + fc->ncols = reg + 1; + fc->col_type = xcrealloc (fc->col_type, fc->ncols, sizeof (short int)); + fc->col_offset = xcrealloc (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 (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_val_offset: + sprintf (tmp, "v%+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; + case DW_CFA_val_expression: + strcpy (tmp, "vexp"); + break; + default: + strcpy (tmp, "n/a"); + break; + } + printf ("%-5s", tmp); + } + } + printf ("\n"); +} + +static int +size_of_encoded_value (int encoding) +{ + switch (encoding & 0x7) + { + default: /* ??? */ + case 0: return eh_addr_size; + case 2: return 2; + case 3: return 4; + case 4: return 8; + } +} + +static dwarf_vma +get_encoded_value (unsigned char *data, int encoding) +{ + int size = size_of_encoded_value (encoding); + if (encoding & DW_EH_PE_signed) + return byte_get_signed (data, size); + else + return byte_get (data, size); +} + +#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 (struct dwarf_section *section, + void *file ATTRIBUTE_UNUSED) +{ + unsigned char *start = section->start; + unsigned char *end = start + section->size; + unsigned char *section_start = start; + Frame_Chunk *chunks = 0; + Frame_Chunk *remembered_state = 0; + Frame_Chunk *rs; + int is_eh = strcmp (section->name, ".eh_frame") == 0; + unsigned int length_return; + int max_regs = 0; + + printf (_("The section %s contains:\n"), section->name); + + 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 = eh_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 = 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 = xmalloc (sizeof (short int)); + fc->col_offset = xmalloc (sizeof (int)); + frame_need_space (fc, max_regs-1); + + version = *start++; + + fc->augmentation = (char *) start; + start = (unsigned char *) strchr ((char *) start, '\0') + 1; + + if (fc->augmentation[0] == 'z') + { + fc->code_factor = LEB (); + fc->data_factor = SLEB (); + if (version == 1) + { + fc->ra = GET (1); + } + else + { + fc->ra = LEB (); + } + augmentation_data_len = LEB (); + augmentation_data = start; + start += augmentation_data_len; + } + else if (strcmp (fc->augmentation, "eh") == 0) + { + start += eh_addr_size; + fc->code_factor = LEB (); + fc->data_factor = SLEB (); + if (version == 1) + { + fc->ra = GET (1); + } + else + { + fc->ra = LEB (); + } + } + else + { + fc->code_factor = LEB (); + fc->data_factor = SLEB (); + if (version == 1) + { + fc->ra = GET (1); + } + else + { + fc->ra = LEB (); + } + } + 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 = (unsigned char *) 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, (unsigned long)(saved_start - section_start)); + start = block_end; + fc->ncols = 0; + fc->col_type = xmalloc (sizeof (short int)); + fc->col_offset = 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 = xcmalloc (fc->ncols, sizeof (short int)); + fc->col_offset = xcmalloc (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 = get_encoded_value (start, fc->fde_encoding); + if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel + /* Don't adjust for relocatable file since there's + invariably a pcrel reloc here, which we haven't + applied. */ + && !is_relocatable) + fc->pc_begin += section->address + (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. */ + /* ??? At present we need to do this always, since this sizes the + fc->col_type and fc->col_offset arrays, which we write into always. + We should probably split the interpreted and non-interpreted bits + into two different routines, since there's so much that doesn't + really overlap between them. */ + if (1 || 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: + case DW_CFA_val_offset: + 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: + case DW_CFA_val_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: + case DW_CFA_val_offset_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; + dwarf_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 = get_encoded_value (start, fc->fde_encoding); + if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel + && !is_relocatable) + vma += section->address + (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_val_offset: + reg = LEB (); + roffs = LEB (); + if (! do_debug_frames_interp) + printf (" DW_CFA_val_offset: r%ld at cfa%+ld\n", + reg, roffs * fc->data_factor); + fc->col_type[reg] = DW_CFA_val_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 in r%ld\n", reg, roffs); + 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 = xmalloc (sizeof (Frame_Chunk)); + rs->ncols = fc->ncols; + rs->col_type = xcmalloc (rs->ncols, sizeof (short int)); + rs->col_offset = xcmalloc (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; + if (rs) + { + 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); + } + else if (do_debug_frames_interp) + printf ("Mismatched DW_CFA_restore_state\n"); + 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, eh_addr_size, ul, 0); + 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, eh_addr_size, ul, 0); + printf (")\n"); + } + fc->col_type[reg] = DW_CFA_expression; + start += ul; + break; + + case DW_CFA_val_expression: + reg = LEB (); + ul = LEB (); + if (! do_debug_frames_interp) + { + printf (" DW_CFA_val_expression: r%ld (", reg); + decode_location_expression (start, eh_addr_size, ul, 0); + printf (")\n"); + } + fc->col_type[reg] = DW_CFA_val_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_val_offset_sf: + reg = LEB (); + l = SLEB (); + frame_need_space (fc, reg); + if (! do_debug_frames_interp) + printf (" DW_CFA_val_offset_sf: r%ld at cfa%+ld\n", + reg, l * fc->data_factor); + fc->col_type[reg] = DW_CFA_val_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_offset = fc->cfa_offset * fc->data_factor; + 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 (); + fc->cfa_offset = fc->cfa_offset * fc->data_factor; + 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: + warn (_("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 (struct dwarf_section *section, + void *file ATTRIBUTE_UNUSED) +{ + printf (_("Displaying the debug contents of section %s is not yet supported.\n"), + section->name); + + return 1; +} + +void * +cmalloc (size_t nmemb, size_t size) +{ + /* Check for overflow. */ + if (nmemb >= ~(size_t) 0 / size) + return NULL; + else + return malloc (nmemb * size); +} + +void * +xcmalloc (size_t nmemb, size_t size) +{ + /* Check for overflow. */ + if (nmemb >= ~(size_t) 0 / size) + return NULL; + else + return xmalloc (nmemb * size); +} + +void * +xcrealloc (void *ptr, size_t nmemb, size_t size) +{ + /* Check for overflow. */ + if (nmemb >= ~(size_t) 0 / size) + return NULL; + else + return xrealloc (ptr, nmemb * size); +} + +void +error (const char *message, ...) +{ + va_list args; + + va_start (args, message); + fprintf (stderr, _("%s: Error: "), program_name); + vfprintf (stderr, message, args); + va_end (args); +} + +void +warn (const char *message, ...) +{ + va_list args; + + va_start (args, message); + fprintf (stderr, _("%s: Warning: "), program_name); + vfprintf (stderr, message, args); + va_end (args); +} + +void +free_debug_memory (void) +{ + enum dwarf_section_display_enum i; + + free_abbrevs (); + + for (i = 0; i < max; i++) + free_debug_section (i); + + if (debug_information) + { + for (i = 0; i < num_debug_info_entries; i++) + { + if (!debug_information [i].max_loc_offsets) + { + free (debug_information [i].loc_offsets); + free (debug_information [i].have_frame_base); + } + if (!debug_information [i].max_range_lists) + free (debug_information [i].range_lists); + } + free (debug_information); + debug_information = NULL; + num_debug_info_entries = 0; + } + +} + +struct dwarf_section_display debug_displays[] = +{ + { { ".debug_abbrev", NULL, 0, 0 }, + display_debug_abbrev, 0, 0 }, + { { ".debug_aranges", NULL, 0, 0 }, + display_debug_aranges, 0, 0 }, + { { ".debug_frame", NULL, 0, 0 }, + display_debug_frames, 1, 0 }, + { { ".debug_info", NULL, 0, 0 }, + display_debug_info, 1, 0 }, + { { ".debug_line", NULL, 0, 0 }, + display_debug_lines, 0, 0 }, + { { ".debug_pubnames", NULL, 0, 0 }, + display_debug_pubnames, 0, 0 }, + { { ".eh_frame", NULL, 0, 0 }, + display_debug_frames, 1, 1 }, + { { ".debug_macinfo", NULL, 0, 0 }, + display_debug_macinfo, 0, 0 }, + { { ".debug_str", NULL, 0, 0 }, + display_debug_str, 0, 0 }, + { { ".debug_loc", NULL, 0, 0 }, + display_debug_loc, 0, 0 }, + { { ".debug_pubtypes", NULL, 0, 0 }, + display_debug_pubnames, 0, 0 }, + { { ".debug_ranges", NULL, 0, 0 }, + display_debug_ranges, 0, 0 }, + { { ".debug_static_func", NULL, 0, 0 }, + display_debug_not_supported, 0, 0 }, + { { ".debug_static_vars", NULL, 0, 0 }, + display_debug_not_supported, 0, 0 }, + { { ".debug_types", NULL, 0, 0 }, + display_debug_not_supported, 0, 0 }, + { { ".debug_weaknames", NULL, 0, 0 }, + display_debug_not_supported, 0, 0 } +}; diff --git a/contrib/binutils-2.17/binutils/dwarf.h b/contrib/binutils-2.17/binutils/dwarf.h new file mode 100644 index 0000000000..907ac93ef7 --- /dev/null +++ b/contrib/binutils-2.17/binutils/dwarf.h @@ -0,0 +1,122 @@ +/* dwwrf.h - DWARF support header file + Copyright 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "bfd.h" +#include "elf/dwarf2.h" + +#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2) +/* We can't use any bfd types here since readelf may define BFD64 and + objdump may not. */ +typedef unsigned long long dwarf_vma; +typedef unsigned long long dwarf_size_type; +#else +typedef unsigned long dwarf_vma; +typedef unsigned long dwarf_size_type; +#endif + +struct dwarf_section +{ + const char *name; + unsigned char *start; + dwarf_vma address; + dwarf_size_type size; +}; + +/* A structure containing the name of a debug section + and a pointer to a function that can decode it. */ +struct dwarf_section_display +{ + struct dwarf_section section; + int (*display) (struct dwarf_section *, void *); + unsigned int relocate : 1; + unsigned int eh_frame : 1; +}; + +enum dwarf_section_display_enum { + abbrev = 0, + aranges, + frame, + info, + line, + pubnames, + eh_frame, + macinfo, + str, + loc, + pubtypes, + ranges, + static_func, + static_vars, + types, + weaknames, + max +}; + +extern struct dwarf_section_display debug_displays []; + +/* This structure records the information that + we extract from the.debug_info section. */ +typedef struct +{ + unsigned int pointer_size; + unsigned long cu_offset; + unsigned long base_address; + /* This is an array of offsets to the location list table. */ + unsigned long *loc_offsets; + int *have_frame_base; + unsigned int num_loc_offsets; + unsigned int max_loc_offsets; + unsigned long *range_lists; + unsigned int num_range_lists; + unsigned int max_range_lists; +} +debug_info; + +extern dwarf_vma (*byte_get) (unsigned char *, int); +extern dwarf_vma byte_get_little_endian (unsigned char *, int); +extern dwarf_vma byte_get_big_endian (unsigned char *, int); + +extern dwarf_vma eh_addr_size; +extern int is_relocatable; + +extern int do_debug_info; +extern int do_debug_abbrevs; +extern int do_debug_lines; +extern int do_debug_pubnames; +extern int do_debug_aranges; +extern int do_debug_ranges; +extern int do_debug_frames; +extern int do_debug_frames_interp; +extern int do_debug_macinfo; +extern int do_debug_str; +extern int do_debug_loc; + +extern int load_debug_section (enum dwarf_section_display_enum, + void *); +extern void free_debug_section (enum dwarf_section_display_enum); + +extern void free_debug_memory (void); + +void *cmalloc (size_t, size_t); +void *xcmalloc (size_t, size_t); +void *xcrealloc (void *, size_t, size_t); + +void error (const char *, ...) ATTRIBUTE_PRINTF_1; +void warn (const char *, ...) ATTRIBUTE_PRINTF_1; diff --git a/contrib/binutils-2.17/binutils/emul_vanilla.c b/contrib/binutils-2.17/binutils/emul_vanilla.c new file mode 100644 index 0000000000..2f34f9d5c2 --- /dev/null +++ b/contrib/binutils-2.17/binutils/emul_vanilla.c @@ -0,0 +1,29 @@ +/* Binutils emulation layer. + Copyright (C) 2002 Free Software Foundation, Inc. + Written by Tom Rix, Red Hat 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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_parse_arg, +}; diff --git a/contrib/binutils-2.17/binutils/filemode.c b/contrib/binutils-2.17/binutils/filemode.c new file mode 100644 index 0000000000..78578c8824 --- /dev/null +++ b/contrib/binutils-2.17/binutils/filemode.c @@ -0,0 +1,248 @@ +/* filemode.c -- make a string describing file modes + Copyright 1985, 1990, 1991, 1994, 1995, 1997, 1999, 2002, 2003, 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#include "bfd.h" +#include "bucomm.h" + +static char ftypelet (unsigned long); +static void setst (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. */ + +/* 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 (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 multiplexer 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 (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 (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.17/binutils/ieee.c b/contrib/binutils-2.17/binutils/ieee.c new file mode 100644 index 0000000000..98ec30de9e --- /dev/null +++ b/contrib/binutils-2.17/binutils/ieee.c @@ -0,0 +1,7399 @@ +/* ieee.c -- Read and write IEEE-695 debugging information. + Copyright 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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. */ + void *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 (struct ieee_info *, const bfd_byte *, const char *); +static void ieee_eof (struct ieee_info *); +static char *savestring (const char *, unsigned long); +static bfd_boolean ieee_read_number + (struct ieee_info *, const bfd_byte **, bfd_vma *); +static bfd_boolean ieee_read_optional_number + (struct ieee_info *, const bfd_byte **, bfd_vma *, bfd_boolean *); +static bfd_boolean ieee_read_id + (struct ieee_info *, const bfd_byte **, const char **, unsigned long *); +static bfd_boolean ieee_read_optional_id + (struct ieee_info *, const bfd_byte **, const char **, unsigned long *, + bfd_boolean *); +static bfd_boolean ieee_read_expression + (struct ieee_info *, const bfd_byte **, bfd_vma *); +static debug_type ieee_builtin_type + (struct ieee_info *, const bfd_byte *, unsigned int); +static bfd_boolean ieee_alloc_type + (struct ieee_info *, unsigned int, bfd_boolean); +static bfd_boolean ieee_read_type_index + (struct ieee_info *, const bfd_byte **, debug_type *); +static int ieee_regno_to_genreg (bfd *, int); +static int ieee_genreg_to_regno (bfd *, int); +static bfd_boolean parse_ieee_bb (struct ieee_info *, const bfd_byte **); +static bfd_boolean parse_ieee_be (struct ieee_info *, const bfd_byte **); +static bfd_boolean parse_ieee_nn (struct ieee_info *, const bfd_byte **); +static bfd_boolean parse_ieee_ty (struct ieee_info *, const bfd_byte **); +static bfd_boolean parse_ieee_atn (struct ieee_info *, const bfd_byte **); +static bfd_boolean ieee_read_cxx_misc + (struct ieee_info *, const bfd_byte **, unsigned long); +static bfd_boolean ieee_read_cxx_class + (struct ieee_info *, const bfd_byte **, unsigned long); +static bfd_boolean ieee_read_cxx_defaults + (struct ieee_info *, const bfd_byte **, unsigned long); +static bfd_boolean ieee_read_reference + (struct ieee_info *, const bfd_byte **); +static bfd_boolean ieee_require_asn + (struct ieee_info *, const bfd_byte **, bfd_vma *); +static bfd_boolean ieee_require_atn65 + (struct ieee_info *, const bfd_byte **, const char **, unsigned long *); + +/* Report an error in the IEEE debugging information. */ + +static void +ieee_error (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 (struct ieee_info *info) +{ + ieee_error (info, (const bfd_byte *) NULL, + _("unexpected end of debugging information")); +} + +/* Save a string in memory. */ + +static char * +savestring (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 (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 (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 (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 (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 (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 (struct ieee_info *info, const bfd_byte *p, + unsigned int indx) +{ + void *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 (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 (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 (void *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 (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 (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 + 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 (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 (struct ieee_info *info, const bfd_byte **pp) +{ + const bfd_byte *ty_start, *ty_var_start, *ty_code_start; + bfd_vma typeindx, varindx, tc; + void *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 (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; + void *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 (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 (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; + void *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 (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) + { + void *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 (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 (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 (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 (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 (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 + (struct ieee_handle *, struct ieee_buflist *); +static bfd_boolean ieee_change_buffer + (struct ieee_handle *, struct ieee_buflist *); +static bfd_boolean ieee_append_buffer + (struct ieee_handle *, struct ieee_buflist *, struct ieee_buflist *); +static bfd_boolean ieee_real_write_byte (struct ieee_handle *, int); +static bfd_boolean ieee_write_2bytes (struct ieee_handle *, int); +static bfd_boolean ieee_write_number (struct ieee_handle *, bfd_vma); +static bfd_boolean ieee_write_id (struct ieee_handle *, const char *); +static bfd_boolean ieee_write_asn + (struct ieee_handle *, unsigned int, bfd_vma); +static bfd_boolean ieee_write_atn65 + (struct ieee_handle *, unsigned int, const char *); +static bfd_boolean ieee_push_type + (struct ieee_handle *, unsigned int, unsigned int, bfd_boolean, + bfd_boolean); +static unsigned int ieee_pop_type (struct ieee_handle *); +static void ieee_pop_unused_type (struct ieee_handle *); +static unsigned int ieee_pop_type_used (struct ieee_handle *, bfd_boolean); +static bfd_boolean ieee_add_range + (struct ieee_handle *, bfd_boolean, bfd_vma, bfd_vma); +static bfd_boolean ieee_start_range (struct ieee_handle *, bfd_vma); +static bfd_boolean ieee_end_range (struct ieee_handle *, bfd_vma); +static bfd_boolean ieee_define_type + (struct ieee_handle *, unsigned int, bfd_boolean, bfd_boolean); +static bfd_boolean ieee_define_named_type + (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 + (struct ieee_handle *, unsigned int); +static struct bfd_hash_entry *ieee_name_type_newfunc + (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); +static bfd_boolean ieee_write_undefined_tag + (struct ieee_name_type_hash_entry *, void *); +static bfd_boolean ieee_finish_compilation_unit (struct ieee_handle *); +static void ieee_add_bb11_blocks (bfd *, asection *, void *); +static bfd_boolean ieee_add_bb11 + (struct ieee_handle *, asection *, bfd_vma, bfd_vma); +static bfd_boolean ieee_output_pending_parms (struct ieee_handle *); +static unsigned int ieee_vis_to_flags (enum debug_visibility); +static bfd_boolean ieee_class_method_var + (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 (void *, const char *); +static bfd_boolean ieee_start_source (void *, const char *); +static bfd_boolean ieee_empty_type (void *); +static bfd_boolean ieee_void_type (void *); +static bfd_boolean ieee_int_type (void *, unsigned int, bfd_boolean); +static bfd_boolean ieee_float_type (void *, unsigned int); +static bfd_boolean ieee_complex_type (void *, unsigned int); +static bfd_boolean ieee_bool_type (void *, unsigned int); +static bfd_boolean ieee_enum_type + (void *, const char *, const char **, bfd_signed_vma *); +static bfd_boolean ieee_pointer_type (void *); +static bfd_boolean ieee_function_type (void *, int, bfd_boolean); +static bfd_boolean ieee_reference_type (void *); +static bfd_boolean ieee_range_type (void *, bfd_signed_vma, bfd_signed_vma); +static bfd_boolean ieee_array_type + (void *, bfd_signed_vma, bfd_signed_vma, bfd_boolean); +static bfd_boolean ieee_set_type (void *, bfd_boolean); +static bfd_boolean ieee_offset_type (void *); +static bfd_boolean ieee_method_type (void *, bfd_boolean, int, bfd_boolean); +static bfd_boolean ieee_const_type (void *); +static bfd_boolean ieee_volatile_type (void *); +static bfd_boolean ieee_start_struct_type + (void *, const char *, unsigned int, bfd_boolean, unsigned int); +static bfd_boolean ieee_struct_field + (void *, const char *, bfd_vma, bfd_vma, enum debug_visibility); +static bfd_boolean ieee_end_struct_type (void *); +static bfd_boolean ieee_start_class_type + (void *, const char *, unsigned int, bfd_boolean, unsigned int, bfd_boolean, + bfd_boolean); +static bfd_boolean ieee_class_static_member + (void *, const char *, const char *, enum debug_visibility); +static bfd_boolean ieee_class_baseclass + (void *, bfd_vma, bfd_boolean, enum debug_visibility); +static bfd_boolean ieee_class_start_method (void *, const char *); +static bfd_boolean ieee_class_method_variant + (void *, const char *, enum debug_visibility, bfd_boolean, bfd_boolean, + bfd_vma, bfd_boolean); +static bfd_boolean ieee_class_static_method_variant + (void *, const char *, enum debug_visibility, bfd_boolean, bfd_boolean); +static bfd_boolean ieee_class_end_method (void *); +static bfd_boolean ieee_end_class_type (void *); +static bfd_boolean ieee_typedef_type (void *, const char *); +static bfd_boolean ieee_tag_type + (void *, const char *, unsigned int, enum debug_type_kind); +static bfd_boolean ieee_typdef (void *, const char *); +static bfd_boolean ieee_tag (void *, const char *); +static bfd_boolean ieee_int_constant (void *, const char *, bfd_vma); +static bfd_boolean ieee_float_constant (void *, const char *, double); +static bfd_boolean ieee_typed_constant (void *, const char *, bfd_vma); +static bfd_boolean ieee_variable + (void *, const char *, enum debug_var_kind, bfd_vma); +static bfd_boolean ieee_start_function (void *, const char *, bfd_boolean); +static bfd_boolean ieee_function_parameter + (void *, const char *, enum debug_parm_kind, bfd_vma); +static bfd_boolean ieee_start_block (void *, bfd_vma); +static bfd_boolean ieee_end_block (void *, bfd_vma); +static bfd_boolean ieee_end_function (void *); +static bfd_boolean ieee_lineno (void *, 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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (*) (struct bfd_hash_entry *, void *)) (func), \ + (info))) + +/* The general routine to write out IEEE debugging information. */ + +bfd_boolean +write_ieee_debugging_info (bfd *abfd, void *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, + sizeof (struct ieee_name_type_hash_entry)) + || !bfd_hash_table_init (&info.tags.root, ieee_name_type_newfunc, + sizeof (struct ieee_name_type_hash_entry))) + 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, (void *) &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, + (void *) &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, (void *) &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 (struct ieee_name_type_hash_entry *h, void *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 (void *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 (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 ((void *) 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 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *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 (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 (void *p ATTRIBUTE_UNUSED, + const char *filename ATTRIBUTE_UNUSED) +{ + return TRUE; +} + +/* Make an empty type. */ + +static bfd_boolean +ieee_empty_type (void *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 (void *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 (void *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 (void *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 (void *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 (void *p, unsigned int size) +{ + return ieee_int_type (p, size, TRUE); +} + +/* Make an enumeration. */ + +static bfd_boolean +ieee_enum_type (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (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 (void *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 (void *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 (void *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 definition, 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 (void *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 (void *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 (void *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 (void *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 (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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (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 ((void *) 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 (void *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 (void *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 (void *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 (void *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.17/binutils/is-ranlib.c b/contrib/binutils-2.17/binutils/is-ranlib.c new file mode 100644 index 0000000000..22ce3aa4ee --- /dev/null +++ b/contrib/binutils-2.17/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.17/binutils/is-strip.c b/contrib/binutils-2.17/binutils/is-strip.c new file mode 100644 index 0000000000..338245d08b --- /dev/null +++ b/contrib/binutils-2.17/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.17/binutils/nm.c b/contrib/binutils-2.17/binutils/nm.c new file mode 100644 index 0000000000..c1fb4d803e --- /dev/null +++ b/contrib/binutils-2.17/binutils/nm.c @@ -0,0 +1,1639 @@ +/* nm.c -- Describe symbol table of a rel file. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 void *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) + +/* The output formatting functions. */ +static void print_object_filename_bsd (char *); +static void print_object_filename_sysv (char *); +static void print_object_filename_posix (char *); +static void print_archive_filename_bsd (char *); +static void print_archive_filename_sysv (char *); +static void print_archive_filename_posix (char *); +static void print_archive_member_bsd (char *, const char *); +static void print_archive_member_sysv (char *, const char *); +static void print_archive_member_posix (char *, const char *); +static void print_symbol_filename_bsd (bfd *, bfd *); +static void print_symbol_filename_sysv (bfd *, bfd *); +static void print_symbol_filename_posix (bfd *, bfd *); +static void print_value (bfd *, bfd_vma); +static void print_symbol_info_bsd (struct extended_symbol_info *, bfd *); +static void print_symbol_info_sysv (struct extended_symbol_info *, bfd *); +static void print_symbol_info_posix (struct extended_symbol_info *, bfd *); + +/* Support for different output formats. */ +struct output_fns + { + /* Print the name of an object file given on the command line. */ + void (*print_object_filename) (char *); + + /* Print the name of an archive file given on the command line. */ + void (*print_archive_filename) (char *); + + /* Print the name of an archive member file. */ + void (*print_archive_member) (char *, const char *); + + /* Print the name of the file (and archive, if there is one) + containing a symbol. */ + void (*print_symbol_filename) (bfd *, bfd *); + + /* Print a line of information about a symbol. */ + void (*print_symbol_info) (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 show_synthetic = 0; /* Display synthesized symbols too. */ +static int line_numbers = 0; /* Print line numbers for symbols. */ +static int allow_special_symbols = 0; /* Allow special 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}, + {"special-syms", no_argument, &allow_special_symbols, 1}, + {"stats", no_argument, &show_stats, 1}, + {"synthetic", no_argument, &show_synthetic, 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 (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\ + --special-syms Include special symbols in the output\n\ + --synthetic Display synthetic symbols as well\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\ + @FILE Read options from FILE\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 (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 (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]; +} + +static const char * +get_symbol_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; + } +} + +/* Print symbol name NAME, read from ABFD, with printf format FORMAT, + demangling it if requested. */ + +static void +print_symname (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); +} + +static void +print_symdef_entry (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)); + } + } +} + +/* 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 (bfd *abfd, bfd_boolean dynamic, void *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 void *) 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 + && bfd_is_target_special_symbol (abfd, sym) + && ! allow_special_symbols) + keep = 0; + + if (keep) + { + memcpy (to, from, size); + to += size; + } + } + + return (to - (bfd_byte *) minisyms) / size; +} + +/* 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 +non_numeric_forward (const void *P_x, const void *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 (const void *x, const void *y) +{ + return - non_numeric_forward (x, y); +} + +static int +numeric_forward (const void *P_x, const void *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 (const void *x, const void *y) +{ + return - numeric_forward (x, y); +} + +static int (*(sorters[2][2])) (const void *, const void *) = +{ + { 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 (const void *P_x, const void *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 (const void *P_x, const void *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 (bfd *abfd, bfd_boolean dynamic, void *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 = 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 void *) 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 void *) (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 void *) 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 ((void *) *symsizesp, symcount, sizeof (struct size_sym), size_forward2); + + return symcount; +} + +/* This function is used to get the relocs for a particular section. + It is called via bfd_map_over_sections. */ + +static void +get_relocs (bfd *abfd, asection *sec, void *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 = 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; +} + +/* Print a single symbol. */ + +static void +print_symbol (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 = 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 = xmalloc (seccount * sizeof *secs); + relocs = xmalloc (seccount * sizeof *relocs); + relcount = xmalloc (seccount * sizeof *relcount); + + info.secs = secs; + info.relocs = relocs; + info.relcount = relcount; + info.syms = syms; + bfd_map_over_sections (abfd, get_relocs, (void *) &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_line (abfd, syms, sym, &filename, &lineno) + || 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'); +} + +/* Print the symbols when sorting by size. */ + +static void +print_size_symbols (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 the symbols. If ARCHIVE_BFD is non-NULL, it is the archive + containing ABFD. */ + +static void +print_symbols (bfd *abfd, bfd_boolean dynamic, void *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); + } +} + +/* If ARCHIVE_BFD is non-NULL, it is the archive containing ABFD. */ + +static void +display_rel_file (bfd *abfd, bfd *archive_bfd) +{ + long symcount; + void *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; + } + + if (show_synthetic && size == sizeof (asymbol *)) + { + asymbol *synthsyms; + long synth_count; + asymbol **static_syms = NULL; + asymbol **dyn_syms = NULL; + long static_count = 0; + long dyn_count = 0; + + if (dynamic) + { + dyn_count = symcount; + dyn_syms = minisyms; + } + else + { + long storage = bfd_get_dynamic_symtab_upper_bound (abfd); + + static_count = symcount; + static_syms = minisyms; + + if (storage > 0) + { + dyn_syms = xmalloc (storage); + dyn_count = bfd_canonicalize_dynamic_symtab (abfd, dyn_syms); + if (dyn_count < 0) + bfd_fatal (bfd_get_filename (abfd)); + } + } + synth_count = bfd_get_synthetic_symtab (abfd, static_count, static_syms, + dyn_count, dyn_syms, &synthsyms); + if (synth_count > 0) + { + asymbol **symp; + void *new_mini; + long i; + + new_mini = xmalloc ((symcount + synth_count + 1) * sizeof (*symp)); + symp = new_mini; + memcpy (symp, minisyms, symcount * sizeof (*symp)); + symp += symcount; + for (i = 0; i < synth_count; i++) + *symp++ = synthsyms + i; + *symp = 0; + minisyms = new_mini; + symcount += synth_count; + } + } + + /* 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); +} + +static void +display_archive (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 (char *filename) +{ + bfd_boolean retval = TRUE; + bfd *file; + char **matching; + + if (get_file_size (filename) < 1) + return FALSE; + + 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; +} + +/* 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 (char *filename) +{ + if (filename_per_file && !filename_per_symbol) + printf ("\n%s:\n", filename); +} + +static void +print_object_filename_sysv (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 (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 (char *filename) +{ + if (filename_per_file) + printf ("\n%s:\n", filename); +} + +static void +print_archive_filename_sysv (char *filename ATTRIBUTE_UNUSED) +{ +} + +static void +print_archive_filename_posix (char *filename ATTRIBUTE_UNUSED) +{ +} + +/* Print the name of an archive member file. */ + +static void +print_archive_member_bsd (char *archive ATTRIBUTE_UNUSED, + const char *filename) +{ + if (!filename_per_symbol) + printf ("\n%s:\n", filename); +} + +static void +print_archive_member_sysv (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 (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 (bfd *archive_bfd, 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 (bfd *archive_bfd, 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 (bfd *archive_bfd, 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 (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 (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, except 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 (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 (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)); + } +} + +int +main (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); + + expandargv (&argc, &argv); + + 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 specifies 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; +} diff --git a/contrib/binutils-2.17/binutils/not-ranlib.c b/contrib/binutils-2.17/binutils/not-ranlib.c new file mode 100644 index 0000000000..6e61331b78 --- /dev/null +++ b/contrib/binutils-2.17/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.17/binutils/not-strip.c b/contrib/binutils-2.17/binutils/not-strip.c new file mode 100644 index 0000000000..854a6697ad --- /dev/null +++ b/contrib/binutils-2.17/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.17/binutils/objcopy.c b/contrib/binutils-2.17/binutils/objcopy.c new file mode 100644 index 0000000000..0e0cfaaccf --- /dev/null +++ b/contrib/binutils-2.17/binutils/objcopy.c @@ -0,0 +1,3301 @@ +/* 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, 2004, 2005, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#include "bfd.h" +#include "progress.h" +#include "bucomm.h" +#include "getopt.h" +#include "libiberty.h" +#include "budbg.h" +#include "filenames.h" +#include "fnmatch.h" +#include "elf-bfd.h" +#include +#include "libbfd.h" + +/* 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; + +#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_NONDEBUG, /* Strip everything but debug info. */ + 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 alternative machine code? */ +static unsigned long use_alt_mach_code = 0; + +/* Output BFD flags user wants to set or clear */ +static flagword bfd_flags_to_set; +static flagword bfd_flags_to_clear; + +/* 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; + +/* If non-NULL the argument to --add-gnu-debuglink. + This should be the filename to store in the .gnu_debuglink section. */ +static const char * gnu_debuglink_filename = NULL; + +/* 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; + +/* Whether to permit wildcard in symbol comparison. */ +static bfd_boolean wildcard = FALSE; + +/* List of symbols to strip, keep, localize, keep-global, weaken, + or redefine. */ +static struct symlist *strip_specific_list = NULL; +static struct symlist *strip_unneeded_list = NULL; +static struct symlist *keep_specific_list = NULL; +static struct symlist *localize_specific_list = NULL; +static struct symlist *globalize_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; + +/* If this is TRUE, we retain BSF_FILE symbols. */ +static bfd_boolean keep_file_symbols = 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. */ +enum command_line_switch + { + OPTION_ADD_SECTION=150, + OPTION_CHANGE_ADDRESSES, + OPTION_CHANGE_LEADING_CHAR, + OPTION_CHANGE_START, + OPTION_CHANGE_SECTION_ADDRESS, + OPTION_CHANGE_SECTION_LMA, + OPTION_CHANGE_SECTION_VMA, + OPTION_CHANGE_WARNINGS, + OPTION_DEBUGGING, + OPTION_GAP_FILL, + OPTION_NO_CHANGE_WARNINGS, + OPTION_PAD_TO, + OPTION_REMOVE_LEADING_CHAR, + OPTION_SET_SECTION_FLAGS, + OPTION_SET_START, + OPTION_STRIP_UNNEEDED, + OPTION_WEAKEN, + OPTION_REDEFINE_SYM, + OPTION_REDEFINE_SYMS, + OPTION_SREC_LEN, + OPTION_SREC_FORCES3, + OPTION_STRIP_SYMBOLS, + OPTION_STRIP_UNNEEDED_SYMBOL, + OPTION_STRIP_UNNEEDED_SYMBOLS, + OPTION_KEEP_SYMBOLS, + OPTION_LOCALIZE_SYMBOLS, + OPTION_GLOBALIZE_SYMBOL, + OPTION_GLOBALIZE_SYMBOLS, + OPTION_KEEPGLOBAL_SYMBOLS, + OPTION_WEAKEN_SYMBOLS, + OPTION_RENAME_SECTION, + OPTION_ALT_MACH_CODE, + OPTION_PREFIX_SYMBOLS, + OPTION_PREFIX_SECTIONS, + OPTION_PREFIX_ALLOC_SECTIONS, + OPTION_FORMATS_INFO, + OPTION_ADD_GNU_DEBUGLINK, + OPTION_ONLY_KEEP_DEBUG, + OPTION_KEEP_FILE_SYMBOLS, + OPTION_READONLY_TEXT, + OPTION_WRITABLE_TEXT, + OPTION_PURE, + OPTION_IMPURE + }; + +/* 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-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS}, + {"keep-symbol", required_argument, 0, 'K'}, + {"only-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG}, + {"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'}, + {"wildcard", no_argument, 0, 'w'}, + {0, no_argument, 0, 0} +}; + +/* Options to handle if running as "objcopy". */ + +static struct option copy_options[] = +{ + {"add-gnu-debuglink", required_argument, 0, OPTION_ADD_GNU_DEBUGLINK}, + {"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}, + {"globalize-symbol", required_argument, 0, OPTION_GLOBALIZE_SYMBOL}, + {"globalize-symbols", required_argument, 0, OPTION_GLOBALIZE_SYMBOLS}, + {"help", no_argument, 0, 'h'}, + {"impure", no_argument, 0, OPTION_IMPURE}, + {"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-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS}, + {"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-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG}, + {"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'}, + {"pure", no_argument, 0, OPTION_PURE}, + {"readonly-text", no_argument, 0, OPTION_READONLY_TEXT}, + {"redefine-sym", required_argument, 0, OPTION_REDEFINE_SYM}, + {"redefine-syms", required_argument, 0, OPTION_REDEFINE_SYMS}, + {"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-unneeded-symbol", required_argument, 0, OPTION_STRIP_UNNEEDED_SYMBOL}, + {"strip-unneeded-symbols", required_argument, 0, OPTION_STRIP_UNNEEDED_SYMBOLS}, + {"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}, + {"wildcard", no_argument, 0, 'w'}, + {"writable-text", no_argument, 0, OPTION_WRITABLE_TEXT}, + {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 and machine of input + binary files. */ +extern enum bfd_architecture bfd_external_binary_architecture; +extern unsigned long bfd_external_machine; + +/* Forward declarations. */ +static void setup_section (bfd *, asection *, void *); +static void setup_bfd_headers (bfd *, bfd *); +static void copy_section (bfd *, asection *, void *); +static void get_sections (bfd *, asection *, void *); +static int compare_section_lma (const void *, const void *); +static void mark_symbols_used_in_relocations (bfd *, asection *, void *); +static bfd_boolean write_debugging_info (bfd *, void *, long *, asymbol ***); +static const char *lookup_sym_redefinition (const char *); + +static void +copy_usage (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\ + --add-gnu-debuglink= Add section .gnu_debuglink linking to \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 & sections\n\ + --strip-unneeded Remove all symbols not needed by relocations\n\ + -N --strip-symbol Do not copy symbol \n\ + --strip-unneeded-symbol \n\ + Do not copy symbol unless needed by\n\ + relocations\n\ + --only-keep-debug Strip everything but the debug information\n\ + -K --keep-symbol Do not strip symbol \n\ + --keep-file-symbols Do not strip file symbol(s)\n\ + -L --localize-symbol Force symbol to be marked as a local\n\ + --globalize-symbol Force symbol to be marked as a global\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\ + -w --wildcard Permit wildcard in symbol comparison\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\ + --redefine-syms --redefine-sym for all symbol pairs \n\ + listed in \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\ + --strip-unneeded-symbols \n\ + --strip-unneeded-symbol for all symbols listed\n\ + in \n\ + --keep-symbols -K for all symbols listed in \n\ + --localize-symbols -L for all symbols listed in \n\ + --globalize-symbols --globalize-symbol for all 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 the target's 'th alternative machine\n\ + --writable-text Mark the output text as writable\n\ + --readonly-text Make the output text write protected\n\ + --pure Mark the output file as demand paged\n\ + --impure Mark the output file as impure\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\ + @ Read options from \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 (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 & sections\n\ + --strip-unneeded Remove all symbols not needed by relocations\n\ + --only-keep-debug Strip everything but the debug information\n\ + -N --strip-symbol= Do not copy symbol \n\ + -K --keep-symbol= Do not strip symbol \n\ + --keep-file-symbols Do not strip file symbol(s)\n\ + -w --wildcard Permit wildcard in symbol comparison\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 (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_COFF_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 (const char *name, bfd_boolean add) +{ + 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 = 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 (const char *name, struct symlist **list) +{ + struct symlist *tmp_list; + + tmp_list = 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 (const char *filename, struct symlist **list) +{ + off_t size; + FILE * f; + char * line; + char * buffer; + unsigned int line_count; + + size = get_file_size (filename); + if (size == 0) + return; + + buffer = xmalloc (size + 2); + f = fopen (filename, FOPEN_RT); + if (f == NULL) + fatal (_("cannot open '%s': %s"), filename, strerror (errno)); + + if (fread (buffer, 1, size, f) == 0 || ferror (f)) + fatal (_("%s: fread failed"), filename); + + fclose (f); + buffer [size] = '\n'; + buffer [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 (_("%s:%d: Ignoring rubbish found on this line"), + filename, line_count); + } + + * 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 (const char *name, struct symlist *list) +{ + struct symlist *tmp_list; + + if (wildcard) + { + for (tmp_list = list; tmp_list; tmp_list = tmp_list->next) + if (*(tmp_list->name) != '!') + { + if (!fnmatch (tmp_list->name, name, 0)) + return TRUE; + } + else + { + if (fnmatch (tmp_list->name + 1, name, 0)) + return TRUE; + } + } + else + { + 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 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) +{ + if (sections_removed || sections_copied) + { + struct section_list *p; + + 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; + } + + if ((bfd_get_section_flags (abfd, sec) & SEC_DEBUGGING) != 0) + { + if (strip_symbols == STRIP_DEBUG + || strip_symbols == STRIP_UNNEEDED + || strip_symbols == STRIP_ALL + || discard_locals == LOCALS_ALL + || convert_debugging) + return TRUE; + + if (strip_symbols == STRIP_NONDEBUG) + return FALSE; + } + + 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 (bfd *abfd, bfd *obfd, asymbol **osyms, + asymbol **isyms, long symcount) +{ + 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_coff_get_comdat_section (abfd, bfd_get_section (sym))) + /* 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 + && !(flags & BSF_KEEP) + && is_specified_symbol (name, strip_unneeded_list)) + keep = 0; + if (!keep + && ((keep_file_symbols && (flags & BSF_FILE)) + || is_specified_symbol (name, keep_specific_list))) + keep = 1; + if (keep && is_strip_section (abfd, bfd_get_section (sym))) + keep = 0; + + if (keep) + { + if ((flags & BSF_GLOBAL) != 0 + && (weaken || is_specified_symbol (name, weaken_specific_list))) + { + sym->flags &= ~ BSF_GLOBAL; + sym->flags |= BSF_WEAK; + } + + if (!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 (!undefined + && (flags & BSF_LOCAL) + && is_specified_symbol (name, globalize_specific_list)) + { + sym->flags &= ~ BSF_LOCAL; + sym->flags |= BSF_GLOBAL; + } + + to[dst_count++] = sym; + } + } + + to[dst_count] = NULL; + + return dst_count; +} + +/* Find the redefined name of symbol SOURCE. */ + +static const char * +lookup_sym_redefinition (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 (const char *cause, 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\""), + cause, source); + + if (strcmp (target, list->target) == 0) + fatal (_("%s: Symbol \"%s\" is target of more than one redefinition"), + cause, target); + } + + new_node = xmalloc (sizeof (struct redefine_node)); + + new_node->source = strdup (source); + new_node->target = strdup (target); + new_node->next = NULL; + + *p = new_node; +} + +/* Handle the --redefine-syms option. Read lines containing "old new" + from the file, and add them to the symbol redefine list. */ + +static void +add_redefine_syms_file (const char *filename) +{ + FILE *file; + char *buf; + size_t bufsize; + size_t len; + size_t outsym_off; + int c, lineno; + + file = fopen (filename, "r"); + if (file == NULL) + fatal (_("couldn't open symbol redefinition file %s (error: %s)"), + filename, strerror (errno)); + + bufsize = 100; + buf = xmalloc (bufsize); + + lineno = 1; + c = getc (file); + len = 0; + outsym_off = 0; + while (c != EOF) + { + /* Collect the input symbol name. */ + while (! IS_WHITESPACE (c) && ! IS_LINE_TERMINATOR (c) && c != EOF) + { + if (c == '#') + goto comment; + buf[len++] = c; + if (len >= bufsize) + { + bufsize *= 2; + buf = xrealloc (buf, bufsize); + } + c = getc (file); + } + buf[len++] = '\0'; + if (c == EOF) + break; + + /* Eat white space between the symbol names. */ + while (IS_WHITESPACE (c)) + c = getc (file); + if (c == '#' || IS_LINE_TERMINATOR (c)) + goto comment; + if (c == EOF) + break; + + /* Collect the output symbol name. */ + outsym_off = len; + while (! IS_WHITESPACE (c) && ! IS_LINE_TERMINATOR (c) && c != EOF) + { + if (c == '#') + goto comment; + buf[len++] = c; + if (len >= bufsize) + { + bufsize *= 2; + buf = xrealloc (buf, bufsize); + } + c = getc (file); + } + buf[len++] = '\0'; + if (c == EOF) + break; + + /* Eat white space at end of line. */ + while (! IS_LINE_TERMINATOR(c) && c != EOF && IS_WHITESPACE (c)) + c = getc (file); + if (c == '#') + goto comment; + /* Handle \r\n. */ + if ((c == '\r' && (c = getc (file)) == '\n') + || c == '\n' || c == EOF) + { + end_of_line: + /* Append the redefinition to the list. */ + if (buf[0] != '\0') + redefine_list_append (filename, &buf[0], &buf[outsym_off]); + + lineno++; + len = 0; + outsym_off = 0; + if (c == EOF) + break; + c = getc (file); + continue; + } + else + fatal (_("%s:%d: garbage found at end of line"), filename, lineno); + comment: + if (len != 0 && (outsym_off == 0 || outsym_off == len)) + fatal (_("%s:%d: missing new symbol name"), filename, lineno); + buf[len++] = '\0'; + + /* Eat the rest of the line and finish it. */ + while (c != '\n' && c != EOF) + c = getc (file); + goto end_of_line; + } + + if (len != 0) + fatal (_("%s:%d: premature end of file"), filename, lineno); + + free (buf); +} + +/* Copy unkown object file IBFD onto OBFD. + Returns TRUE upon success, FALSE otherwise. */ + +static bfd_boolean +copy_unknown_object (bfd *ibfd, bfd *obfd) +{ + char *cbuf; + int tocopy; + long ncopied; + long size; + struct stat buf; + + if (bfd_stat_arch_elt (ibfd, &buf) != 0) + { + bfd_nonfatal (bfd_get_archive_filename (ibfd)); + return FALSE; + } + + size = buf.st_size; + if (size < 0) + { + non_fatal (_("stat returns negative size for `%s'"), + bfd_get_archive_filename (ibfd)); + return FALSE; + } + + if (bfd_seek (ibfd, (file_ptr) 0, SEEK_SET) != 0) + { + bfd_nonfatal (bfd_get_archive_filename (ibfd)); + return FALSE; + } + + if (verbose) + printf (_("copy from `%s' [unknown] to `%s' [unknown]\n"), + bfd_get_archive_filename (ibfd), bfd_get_filename (obfd)); + + cbuf = xmalloc (BUFSIZE); + ncopied = 0; + while (ncopied < size) + { + tocopy = size - ncopied; + if (tocopy > BUFSIZE) + tocopy = BUFSIZE; + + if (bfd_bread (cbuf, (bfd_size_type) tocopy, ibfd) + != (bfd_size_type) tocopy) + { + bfd_nonfatal (bfd_get_archive_filename (ibfd)); + free (cbuf); + return FALSE; + } + + if (bfd_bwrite (cbuf, (bfd_size_type) tocopy, obfd) + != (bfd_size_type) tocopy) + { + bfd_nonfatal (bfd_get_filename (obfd)); + free (cbuf); + return FALSE; + } + + ncopied += tocopy; + } + + chmod (bfd_get_filename (obfd), buf.st_mode); + free (cbuf); + return TRUE; +} + +/* Copy object file IBFD onto OBFD. + Returns TRUE upon success, FALSE otherwise. */ + +static bfd_boolean +copy_object (bfd *ibfd, bfd *obfd) +{ + bfd_vma start; + long symcount; + asection **osections = NULL; + asection *gnu_debuglink_section = NULL; + bfd_size_type *gaps = NULL; + bfd_size_type max_gap = 0; + long symsize; + void *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)")); + + if (!bfd_set_format (obfd, bfd_get_format (ibfd))) + { + bfd_nonfatal (bfd_get_filename (obfd)); + return FALSE; + } + + if (verbose) + printf (_("copy from `%s' [%s] to `%s' [%s]\n"), + bfd_get_archive_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) + { + flagword flags; + + flags = bfd_get_file_flags (ibfd); + flags |= bfd_flags_to_set; + flags &= ~bfd_flags_to_clear; + flags &= bfd_applicable_file_flags (obfd); + + if (!bfd_set_start_address (obfd, start) + || !bfd_set_file_flags (obfd, flags)) + { + bfd_nonfatal (bfd_get_archive_filename (ibfd)); + return FALSE; + } + } + + /* 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))) + { + if (bfd_get_arch (ibfd) == bfd_arch_unknown) + non_fatal (_("Unable to recognise the format of the input file `%s'"), + bfd_get_archive_filename (ibfd)); + else + non_fatal (_("Warning: Output file cannot represent architecture `%s'"), + bfd_printable_arch_mach (bfd_get_arch (ibfd), + bfd_get_mach (ibfd))); + return FALSE; + } + + if (!bfd_set_format (obfd, bfd_get_format (ibfd))) + { + bfd_nonfatal (bfd_get_archive_filename (ibfd)); + return FALSE; + } + + if (isympp) + free (isympp); + + if (osympp != isympp) + free (osympp); + + isympp = NULL; + osympp = NULL; + + /* 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, obfd); + + setup_bfd_headers (ibfd, obfd); + + if (add_sections != NULL) + { + struct section_add *padd; + struct section_list *pset; + + for (padd = add_sections; padd != NULL; padd = padd->next) + { + flagword flags; + + pset = find_section_list (padd->name, FALSE); + if (pset != NULL) + pset->used = TRUE; + + flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA; + if (pset != NULL && pset->set_flags) + flags = pset->flags | SEC_HAS_CONTENTS; + + /* bfd_make_section_with_flags() does not return very helpful + error codes, so check for the most likely user error first. */ + if (bfd_get_section_by_name (obfd, padd->name)) + { + non_fatal (_("can't add section '%s' - it already exists!"), padd->name); + return FALSE; + } + else + { + padd->section = bfd_make_section_with_flags (obfd, padd->name, flags); + if (padd->section == NULL) + { + non_fatal (_("can't create section `%s': %s"), + padd->name, bfd_errmsg (bfd_get_error ())); + return FALSE; + } + } + + if (! bfd_set_section_size (obfd, padd->section, padd->size)) + { + bfd_nonfatal (bfd_get_filename (obfd)); + return FALSE; + } + + if (pset != NULL) + { + if (pset->change_vma != CHANGE_IGNORE) + if (! bfd_set_section_vma (obfd, padd->section, + pset->vma_val)) + { + bfd_nonfatal (bfd_get_filename (obfd)); + return FALSE; + } + + 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))) + { + bfd_nonfatal (bfd_get_filename (obfd)); + return FALSE; + } + } + } + } + } + + if (gnu_debuglink_filename != NULL) + { + gnu_debuglink_section = bfd_create_gnu_debuglink_section + (obfd, gnu_debuglink_filename); + + if (gnu_debuglink_section == NULL) + { + bfd_nonfatal (gnu_debuglink_filename); + return FALSE; + } + + /* Special processing for PE format files. We + have no way to distinguish PE from COFF here. */ + if (bfd_get_flavour (obfd) == bfd_target_coff_flavour) + { + bfd_vma debuglink_vma; + asection * highest_section; + asection * sec; + + /* The PE spec requires that all sections be adjacent and sorted + in ascending order of VMA. It also specifies that debug + sections should be last. This is despite the fact that debug + sections are not loaded into memory and so in theory have no + use for a VMA. + + This means that the debuglink section must be given a non-zero + VMA which makes it contiguous with other debug sections. So + walk the current section list, find the section with the + highest VMA and start the debuglink section after that one. */ + for (sec = obfd->sections, highest_section = NULL; + sec != NULL; + sec = sec->next) + if (sec->vma > 0 + && (highest_section == NULL + || sec->vma > highest_section->vma)) + highest_section = sec; + + if (highest_section) + debuglink_vma = BFD_ALIGN (highest_section->vma + + highest_section->size, + /* FIXME: We ought to be using + COFF_PAGE_SIZE here or maybe + bfd_get_section_alignment() (if it + was set) but since this is for PE + and we know the required alignment + it is easier just to hard code it. */ + 0x1000); + else + /* Umm, not sure what to do in this case. */ + debuglink_vma = 0x1000; + + bfd_set_section_vma (obfd, gnu_debuglink_section, debuglink_vma); + } + } + + if (bfd_count_sections (obfd) == 0) + { + non_fatal (_("there are no sections to be copied!")); + return FALSE; + } + + 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 = xmalloc (c * sizeof (asection *)); + set = osections; + bfd_map_over_sections (obfd, get_sections, &set); + + qsort (osections, c, sizeof (asection *), compare_section_lma); + + gaps = 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) + { + bfd_nonfatal (bfd_get_archive_filename (ibfd)); + return FALSE; + } + + osympp = isympp = xmalloc (symsize); + symcount = bfd_canonicalize_symtab (ibfd, isympp); + if (symcount < 0) + { + bfd_nonfatal (bfd_get_filename (ibfd)); + return FALSE; + } + + if (convert_debugging) + dhandle = read_debugging_info (ibfd, isympp, symcount); + + if (strip_symbols == STRIP_DEBUG + || strip_symbols == STRIP_ALL + || strip_symbols == STRIP_UNNEEDED + || strip_symbols == STRIP_NONDEBUG + || discard_locals != LOCALS_UNDEF + || strip_specific_list != NULL + || keep_specific_list != NULL + || localize_specific_list != NULL + || globalize_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, + isympp); + osympp = 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 FALSE; + } + } + + bfd_set_symtab (obfd, osympp, symcount); + + /* This has to happen after the symbol table has been set. */ + bfd_map_over_sections (ibfd, copy_section, 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, padd->contents, + 0, padd->size)) + { + bfd_nonfatal (bfd_get_filename (obfd)); + return FALSE; + } + } + } + + if (gnu_debuglink_filename != NULL) + { + if (! bfd_fill_in_gnu_debuglink_section + (obfd, gnu_debuglink_section, gnu_debuglink_filename)) + { + bfd_nonfatal (gnu_debuglink_filename); + return FALSE; + } + } + + 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 = xmalloc (max_gap); + memset (buf, gap_fill, 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)) + { + bfd_nonfatal (bfd_get_filename (obfd)); + return FALSE; + } + + 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_get_flavour (ibfd) == bfd_target_elf_flavour + && strip_symbols == STRIP_NONDEBUG) + /* Do not copy the private data when creating an ELF format + debug info file. We do not want the program headers. */ + ; + else 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 ())); + return FALSE; + } + + /* 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 (_("this target does not support %lu alternative machine codes"), + use_alt_mach_code); + if (bfd_get_flavour (obfd) == bfd_target_elf_flavour) + { + non_fatal (_("treating that number as an absolute e_machine value instead")); + elf_elfheader (obfd)->e_machine = use_alt_mach_code; + } + else + non_fatal (_("ignoring the alternative value")); + } + } + + return TRUE; +} + +#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 (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 != NULL) + { + char *output_name; + bfd *output_bfd; + bfd *last_element; + struct stat buf; + int stat_status = 0; + bfd_boolean delete = TRUE; + + /* 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 = 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 = xmalloc (sizeof (struct name_list)); + l->name = output_name; + l->next = list; + l->obfd = NULL; + list = l; + + if (output_bfd == NULL) + RETURN_NONFATAL (output_name); + + if (bfd_check_format (this_element, bfd_object)) + { + delete = ! copy_object (this_element, output_bfd); + + if (! delete + || bfd_get_arch (this_element) != bfd_arch_unknown) + { + if (!bfd_close (output_bfd)) + { + bfd_nonfatal (bfd_get_filename (output_bfd)); + /* Error in new object file. Don't change archive. */ + status = 1; + } + } + else + goto copy_unknown_element; + } + else + { + non_fatal (_("Unable to recognise the format of the input file `%s'"), + bfd_get_archive_filename (this_element)); + +copy_unknown_element: + delete = !copy_unknown_object (this_element, output_bfd); + if (!bfd_close_all_done (output_bfd)) + { + bfd_nonfatal (bfd_get_filename (output_bfd)); + /* Error in new object file. Don't change archive. */ + status = 1; + } + } + + if (delete) + { + unlink (output_name); + status = 1; + } + else + { + 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 = 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 (const char *input_filename, const char *output_filename, + const char *input_target, const char *output_target) +{ + bfd *ibfd; + char **obj_matching; + char **core_matching; + + if (get_file_size (input_filename) < 1) + { + non_fatal (_("error: the input file '%s' is empty"), input_filename); + status = 1; + return; + } + + /* 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); + + if (! copy_object (ibfd, obfd)) + status = 1; + + 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 (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 = 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 (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; +} + +/* Once each of the sections is copied, we may still need to do some + finalization work for private section headers. Do that here. */ + +static void +setup_bfd_headers (bfd *ibfd, bfd *obfd) +{ + const char *err; + + /* Allow the BFD backend to copy any private data it understands + from the input section to the output section. */ + if (! bfd_copy_private_header_data (ibfd, obfd)) + { + err = _("private header data"); + goto loser; + } + + /* All went well. */ + return; + +loser: + non_fatal (_("%s: error in %s: %s"), + bfd_get_filename (ibfd), + err, bfd_errmsg (bfd_get_error ())); + status = 1; +} + +/* Create a section in OBFD with the same + name and attributes as ISECTION in IBFD. */ + +static void +setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) +{ + bfd *obfd = 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 (is_strip_section (ibfd, isection)) + return; + + p = find_section_list (bfd_section_name (ibfd, isection), FALSE); + if (p != NULL) + p->used = TRUE; + + /* 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; + } + + if (p != NULL && p->set_flags) + flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC)); + else if (strip_symbols == STRIP_NONDEBUG && (flags & SEC_ALLOC) != 0) + flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD); + + osection = bfd_make_section_anyway_with_flags (obfd, name, flags); + + if (osection == NULL) + { + err = _("making"); + goto loser; + } + + if (strip_symbols == STRIP_NONDEBUG + && obfd->xvec->flavour == bfd_target_elf_flavour + && (flags & SEC_ALLOC) != 0 + && (p == NULL || !p->set_flags)) + elf_section_type (osection) = SHT_NOBITS; + + 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; + } + + /* 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_get_flavour (ibfd) == bfd_target_elf_flavour + && strip_symbols == STRIP_NONDEBUG) + /* Do not copy the private data when creating an ELF format + debug info file. We do not want the program headers. */ + ; + else 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 (bfd *ibfd, sec_ptr isection, void *obfdarg) +{ + bfd *obfd = 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; + + if (is_strip_section (ibfd, isection)) + return; + + flags = bfd_get_section_flags (ibfd, isection); + if ((flags & SEC_GROUP) != 0) + return; + + osection = isection->output_section; + size = bfd_get_section_size (isection); + + if (size == 0 || osection == 0) + return; + + p = find_section_list (bfd_get_section_name (ibfd, isection), FALSE); + + /* 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) + { + /* Do not complain if the target does not support relocations. */ + if (relsize == -1 && bfd_get_error () == bfd_error_invalid_operation) + relsize = 0; + else + RETURN_NONFATAL (bfd_get_filename (ibfd)); + } + } + + if (relsize == 0) + bfd_set_reloc (obfd, osection, NULL, 0); + else + { + relpp = 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 = 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 ? NULL : relpp, relcount); + if (relcount == 0) + free (relpp); + } + + if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS + && bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS) + { + void *memhunk = xmalloc (size); + + if (!bfd_get_section_contents (ibfd, isection, memhunk, 0, size)) + RETURN_NONFATAL (bfd_get_filename (ibfd)); + + if (copy_byte >= 0) + { + /* Keep only every `copy_byte'th byte in MEMHUNK. */ + char *from = (char *) memhunk + copy_byte; + char *to = memhunk; + char *end = (char *) memhunk + size; + + for (; from < end; from += interleave) + *to++ = *from; + + size = (size + interleave - 1 - copy_byte) / interleave; + osection->lma /= interleave; + } + + if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size)) + RETURN_NONFATAL (bfd_get_filename (obfd)); + + free (memhunk); + } + else if (p != NULL && p->set_flags && (p->flags & SEC_HAS_CONTENTS) != 0) + { + void *memhunk = xmalloc (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, 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 (bfd *obfd ATTRIBUTE_UNUSED, asection *osection, void *secppparg) +{ + asection ***secppp = 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 (const void *arg1, const void *arg2) +{ + const asection *const *sec1 = arg1; + const asection *const *sec2 = 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 (bfd_get_section_size (*sec1) > bfd_get_section_size (*sec2)) + return 1; + else if (bfd_get_section_size (*sec1) < bfd_get_section_size (*sec2)) + 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 (bfd *ibfd, sec_ptr isection, void *symbolsarg) +{ + asymbol **symbols = 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) + { + /* Do not complain if the target does not support relocations. */ + if (relsize == -1 && bfd_get_error () == bfd_error_invalid_operation) + return; + bfd_fatal (bfd_get_filename (ibfd)); + } + + if (relsize == 0) + return; + + relpp = 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 (bfd *obfd, void *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; + flagword flags; + + if (! write_stabs_in_sections_debugging_info (obfd, dhandle, &syms, + &symsize, &strings, + &stringsize)) + return FALSE; + + flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DEBUGGING; + stabsec = bfd_make_section_with_flags (obfd, ".stab", flags); + stabstrsec = bfd_make_section_with_flags (obfd, ".stabstr", flags); + 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)) + { + 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, 0, symsize) + || ! bfd_set_section_contents (obfd, stabstrsec, strings, 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 (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:sSpdgxXHhVvw", + 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 OPTION_ONLY_KEEP_DEBUG: + strip_symbols = STRIP_NONDEBUG; + break; + case OPTION_KEEP_FILE_SYMBOLS: + keep_file_symbols = 1; + break; + case 0: + /* We've been given a long option. */ + break; + case 'w': + wildcard = TRUE; + 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 == 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 (get_file_size (argv[i]) < 1) + continue; + + if (preserve_dates) + /* No need to check the return value of stat(). + It has already been checked in get_file_size(). */ + stat (argv[i], &statbuf); + + 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_if_ordinary (tmpname); + if (output_file == NULL) + free (tmpname); + } + + return 0; +} + +static int +copy_main (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:w", + 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 OPTION_ONLY_KEEP_DEBUG: + strip_symbols = STRIP_NONDEBUG; + break; + + case OPTION_KEEP_FILE_SYMBOLS: + keep_file_symbols = 1; + break; + + case OPTION_ADD_GNU_DEBUGLINK: + gnu_debuglink_filename = optarg; + break; + + case 'K': + add_specific_symbol (optarg, &keep_specific_list); + break; + + case 'N': + add_specific_symbol (optarg, &strip_specific_list); + break; + + case OPTION_STRIP_UNNEEDED_SYMBOL: + add_specific_symbol (optarg, &strip_unneeded_list); + break; + + case 'L': + add_specific_symbol (optarg, &localize_specific_list); + break; + + case OPTION_GLOBALIZE_SYMBOL: + add_specific_symbol (optarg, &globalize_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 'w': + wildcard = 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; + off_t size; + struct section_add *pa; + int len; + char *name; + FILE *f; + + s = strchr (optarg, '='); + + if (s == NULL) + fatal (_("bad format for %s"), "--add-section"); + + size = get_file_size (s + 1); + if (size < 1) + break; + + pa = xmalloc (sizeof (struct section_add)); + + len = s - optarg; + name = xmalloc (len + 1); + strncpy (name, optarg, len); + name[len] = '\0'; + pa->name = name; + + pa->filename = s + 1; + pa->size = size; + pa->contents = xmalloc (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 = 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 = xmalloc (len + 1); + strncpy (source, optarg, len); + source[len] = '\0'; + + nextarg = s + 1; + len = strlen (nextarg); + target = xmalloc (len + 1); + strcpy (target, nextarg); + + redefine_list_append ("--redefine-sym", source, target); + + free (source); + free (target); + } + break; + + case OPTION_REDEFINE_SYMS: + add_redefine_syms_file (optarg); + 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 = 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 = 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 = 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_STRIP_UNNEEDED_SYMBOLS: + add_specific_symbols (optarg, &strip_unneeded_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_GLOBALIZE_SYMBOLS: + add_specific_symbols (optarg, &globalize_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 = strtoul (optarg, NULL, 0); + if (use_alt_mach_code == 0) + fatal (_("unable to parse alternative machine code")); + 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 OPTION_READONLY_TEXT: + bfd_flags_to_set |= WP_TEXT; + bfd_flags_to_clear &= ~WP_TEXT; + break; + + case OPTION_WRITABLE_TEXT: + bfd_flags_to_clear |= WP_TEXT; + bfd_flags_to_set &= ~WP_TEXT; + break; + + case OPTION_PURE: + bfd_flags_to_set |= D_PAGED; + bfd_flags_to_clear &= ~D_PAGED; + break; + + case OPTION_IMPURE: + bfd_flags_to_clear |= D_PAGED; + bfd_flags_to_set &= ~D_PAGED; + break; + + case 0: + /* We've been given a long option. */ + break; + + 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 == NULL) + output_target = input_target; + + if (binary_architecture != 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; + bfd_external_machine = temp_arch_info->mach; + } + 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 (_("warning: could not locate '%s'. System error message: %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 == 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); + else if (status != 0) + unlink_if_ordinary (output_filename); + } + + 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 (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); + + expandargv (&argc, &argv); + + 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.17/binutils/objdump.c b/contrib/binutils-2.17/binutils/objdump.c new file mode 100644 index 0000000000..6e5eab56da --- /dev/null +++ b/contrib/binutils-2.17/binutils/objdump.c @@ -0,0 +1,3188 @@ +/* objdump.c -- dump information about an object file. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004, 2005, 2006 + 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, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Objdump overview. + + Objdump displays information about one or more object files, either on + their own, or inside libraries. It is commonly used as a disassembler, + but it can also display information about file headers, symbol tables, + relocations, debugging directives and more. + + The flow of execution is as follows: + + 1. Command line arguments are checked for control switches and the + information to be displayed is selected. + + 2. Any remaining arguments are assumed to be object files, and they are + processed in order by display_bfd(). If the file is an archive each + of its elements is processed in turn. + + 3. The file's target architecture and binary file format are determined + by bfd_check_format(). If they are recognised, then dump_bfd() is + called. + + 4. dump_bfd() in turn calls separate functions to display the requested + item(s) of information(s). For example disassemble_data() is called if + a disassembly has been requested. + + When disassembling the code loops through blocks of instructions bounded + by symbols, calling disassemble_bytes() on each block. The actual + disassembling is done by the libopcodes library, via a function pointer + supplied by the disassembler() function. */ + +#include "bfd.h" +#include "bfdver.h" +#include "progress.h" +#include "bucomm.h" +#include "dwarf.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" + +/* Exit status. */ +static int exit_status = 0; + +static char *default_target = NULL; /* Default at runtime. */ + +/* The following variables are set based on arguments passed on the + command line. */ +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_dwarf_section_info; /* --dwarf */ +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 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 int dump_debugging_tags; /* --debugging-tags */ +static int dump_special_syms = 0; /* --special-syms */ +static bfd_vma adjust_section_vma = 0; /* --adjust-vma */ +static int file_start_context = 0; /* --file-start-context */ + +/* Pointer to an array of section names provided by + one or more "-j secname" command line options. */ +static char **only; +/* The total number of slots in the only[] array. */ +static size_t only_size = 0; +/* The number of occupied slots in the only[] array. */ +static size_t only_used = 0; + +/* Variables for handling include file path table. */ +static const char **include_paths; +static int include_path_count; + +/* Extra info to pass to the section disassembler and address printing + function. */ +struct objdump_disasm_info +{ + bfd * abfd; + asection * sec; + bfd_boolean require_sec; + arelent ** dynrelbuf; + long dynrelcount; + disassembler_ftype disassemble_fn; + arelent * reloc; +}; + +/* Architecture to disassemble for, or default if NULL. */ +static char *machine = NULL; + +/* Target specific options to the disassembler. */ +static char *disassembler_options = 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; + +/* The synthetic symbol table. */ +static asymbol *synthsyms; +static long synthcount = 0; + +/* 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 void +usage (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\ + -e, --debugging-tags Display debug information using ctags style\n\ + -G, --stabs Display (in raw form) any STABS info in the file\n\ + -W, --dwarf Display DWARF 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\ + @ Read options from \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\ + -I, --include=DIR Add DIR to search list for source files\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\ + --special-syms Include special symbols in symbol dumps\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. */ +enum option_values + { + OPTION_ENDIAN=150, + OPTION_START_ADDRESS, + OPTION_STOP_ADDRESS, + OPTION_ADJUST_VMA + }; + +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'}, + {"debugging-tags", no_argument, NULL, 'e'}, + {"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'}, + {"special-syms", no_argument, &dump_special_syms, 1}, + {"include", required_argument, NULL, 'I'}, + {"dwarf", no_argument, NULL, 'W'}, + {"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 (const char *msg) +{ + bfd_nonfatal (msg); + exit_status = 1; +} + +static void +dump_section_header (bfd *abfd, asection *section, + void *ignored ATTRIBUTE_UNUSED) +{ + char *comma = ""; + unsigned int opb = bfd_octets_per_byte (abfd); + + /* Ignore linker created section. See elfNN_ia64_object_p in + bfd/elfxx-ia64.c. */ + if (section->flags & SEC_LINKER_CREATED) + return; + + 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"); + if (bfd_get_arch (abfd) == bfd_arch_tic54x) + { + PF (SEC_TIC54X_BLOCK, "BLOCK"); + PF (SEC_TIC54X_CLINK, "CLINK"); + } + PF (SEC_SMALL_DATA, "SMALL_DATA"); + if (bfd_get_flavour (abfd) == bfd_target_coff_flavour) + PF (SEC_COFF_SHARED, "SHARED"); + PF (SEC_THREAD_LOCAL, "THREAD_LOCAL"); + PF (SEC_GROUP, "GROUP"); + + if ((section->flags & SEC_LINK_ONCE) != 0) + { + const char *ls; + struct coff_comdat_info *comdat; + + 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); + + comdat = bfd_coff_get_comdat_section (abfd, section); + if (comdat != NULL) + printf (" (COMDAT %s %ld)", comdat->name, comdat->symbol); + + comma = ", "; + } + + printf ("\n"); +#undef PF +} + +static void +dump_headers (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, NULL); +} + +static asymbol ** +slurp_symtab (bfd *abfd) +{ + asymbol **sy = 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 = 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 (bfd *abfd) +{ + asymbol **sy = 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 = 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 (asymbol **symbols, long count) +{ + 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 | BSF_SECTION_SYM)) + 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 (const void *ap, const void *bp) +{ + const asymbol *a = * (const asymbol **) ap; + const asymbol *b = * (const asymbol **) bp; + const char *an; + const char *bn; + size_t anl; + size_t bnl; + bfd_boolean af; + bfd_boolean bf; + flagword aflags; + flagword 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 (const void *ap, const void *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 an address (VMA) to the output stream in INFO. + If SKIP_ZEROES is TRUE, omit leading zeroes. */ + +static void +objdump_print_value (bfd_vma vma, struct disassemble_info *info, + bfd_boolean skip_zeroes) +{ + char buf[30]; + char *p; + struct objdump_disasm_info *aux; + + 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 (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 and a section (from INFO->application_data), + and a VMA. If INFO->application_data->require_sec is TRUE, then always + require the symbol to be in the section. 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 (bfd_vma vma, + struct disassemble_info *info, + 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; + struct objdump_disasm_info *aux; + bfd *abfd; + asection *sec; + unsigned int opb; + + if (sorted_symcount < 1) + return NULL; + + aux = (struct objdump_disasm_info *) info->application_data; + abfd = aux->abfd; + sec = aux->sec; + opb = bfd_octets_per_byte (abfd); + + /* 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 relocatable, 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 + && (aux->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 + && (aux->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; + } + + /* Give the target a chance to reject the symbol. */ + while (! info->symbol_is_valid (sorted_syms [thisplace], info)) + { + ++ thisplace; + if (thisplace >= sorted_symcount + || bfd_asymbol_value (sorted_syms [thisplace]) > vma) + return NULL; + } + + if (place != NULL) + *place = thisplace; + + return sorted_syms[thisplace]; +} + +/* Print an address and the offset to the nearest symbol. */ + +static void +objdump_print_addr_with_sym (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 an address (VMA), symbolically if possible. + If SKIP_ZEROES is TRUE, don't output leading zeroes. */ + +static void +objdump_print_addr (bfd_vma vma, + struct disassemble_info *info, + bfd_boolean skip_zeroes) +{ + struct objdump_disasm_info *aux; + asymbol *sym = NULL; /* Initialize to avoid compiler warning. */ + bfd_boolean skip_find = FALSE; + + 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; + + if (aux->reloc != NULL + && aux->reloc->sym_ptr_ptr != NULL + && * aux->reloc->sym_ptr_ptr != NULL) + { + sym = * aux->reloc->sym_ptr_ptr; + + /* Adjust the vma to the reloc. */ + vma += bfd_asymbol_value (sym); + + if (bfd_is_und_section (bfd_get_section (sym))) + skip_find = TRUE; + } + + if (!skip_find) + sym = find_symbol_for_address (vma, info, 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 (bfd_vma vma, struct disassemble_info *info) +{ + objdump_print_addr (vma, info, ! prefix_addresses); +} + +/* Determine if the given address has a symbol associated with it. */ + +static int +objdump_symbol_at_address (bfd_vma vma, struct disassemble_info * info) +{ + asymbol * sym; + + sym = find_symbol_for_address (vma, info, 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 + disassembly 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; + const char *filename; + const char *modname; + 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) + +/* Tries to open MODNAME, and if successful adds a node to print_files + linked list and returns that node. Returns NULL on failure. */ + +static struct print_file_list * +try_print_file_open (const char *origname, const char *modname) +{ + struct print_file_list *p; + FILE *f; + + f = fopen (modname, "r"); + if (f == NULL) + return NULL; + + if (print_files != NULL && print_files->f != NULL) + { + fclose (print_files->f); + print_files->f = NULL; + } + + p = xmalloc (sizeof (struct print_file_list)); + p->filename = origname; + p->modname = modname; + p->line = 0; + p->f = f; + p->next = print_files; + print_files = p; + return p; +} + +/* If the the source file, as described in the symtab, is not found + try to locate it in one of the paths specified with -I + If found, add location to print_files linked list. */ + +static struct print_file_list * +update_source_path (const char *filename) +{ + struct print_file_list *p; + const char *fname; + int i; + + if (filename == NULL) + return NULL; + + p = try_print_file_open (filename, filename); + if (p != NULL) + return p; + + if (include_path_count == 0) + return NULL; + + /* Get the name of the file. */ + fname = strrchr (filename, '/'); +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + { + /* We could have a mixed forward/back slash case. */ + char *backslash = strrchr (filename, '\\'); + if (fname == NULL || (backslash != NULL && backslash > fname)) + fname = backslash; + if (fname == NULL && filename[0] != '\0' && filename[1] == ':') + fname = filename + 1; + } +#endif + if (fname == NULL) + fname = filename; + else + ++fname; + + /* If file exists under a new path, we need to add it to the list + so that show_line knows about it. */ + for (i = 0; i < include_path_count; i++) + { + char *modname = concat (include_paths[i], "/", fname, (const char *) 0); + + p = try_print_file_open (filename, modname); + if (p) + return p; + + free (modname); + } + + return NULL; +} + +/* Skip ahead to a given line in a file, optionally printing each + line. */ + +static void +skip_to_line (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 disassembly + listing. */ + +static void +show_line (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->modname, "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 + { + p = update_source_path (filename); + + if (p != NULL) + { + int l; + + 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 pos; + size_t alloc; +} SFILE; + +/* sprintf to a "stream". */ + +static int ATTRIBUTE_PRINTF_2 +objdump_sprintf (SFILE *f, const char *format, ...) +{ + size_t n; + va_list args; + + while (1) + { + size_t space = f->alloc - f->pos; + + va_start (args, format); + n = vsnprintf (f->buffer + f->pos, space, format, args); + va_end (args); + + if (space > n) + break; + + f->alloc = (f->alloc + n) * 2; + f->buffer = xrealloc (f->buffer, f->alloc); + } + f->pos += n; + + return n; +} + +/* Returns TRUE if the specified section should be dumped. */ + +static bfd_boolean +process_section_p (asection * section) +{ + size_t i; + + if (only == NULL) + return TRUE; + + for (i = 0; i < only_used; i++) + if (strcmp (only [i], section->name) == 0) + return TRUE; + + return FALSE; +} + + +/* The number of zeroes we want to see before we start skipping them. + The number is arbitrarily chosen. */ + +#define DEFAULT_SKIP_ZEROES 8 + +/* 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. */ + +#define DEFAULT_SKIP_ZEROES_AT_END 3 + +/* Disassemble some data in memory between given values. */ + +static void +disassemble_bytes (struct disassemble_info * info, + disassembler_ftype disassemble_fn, + bfd_boolean insns, + bfd_byte * data, + bfd_vma start_offset, + bfd_vma stop_offset, + bfd_vma rel_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; + unsigned int opb = info->octets_per_byte; + unsigned int skip_zeroes = info->skip_zeroes; + unsigned int skip_zeroes_at_end = info->skip_zeroes_at_end; + int octets = opb; + SFILE sfile; + + aux = (struct objdump_disasm_info *) info->application_data; + section = aux->sec; + + sfile.alloc = 120; + sfile.buffer = xmalloc (sfile.alloc); + sfile.pos = 0; + + 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; + bfd_boolean need_nl = FALSE; + int previous_octets; + + /* Remember the length of the previous instruction. */ + previous_octets = octets; + octets = 0; + + /* 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]; + int bpc = 0; + int pb = 0; + + done_dot = FALSE; + + if (with_line_numbers || with_source_code) + show_line (aux->abfd, section, addr_offset); + + 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.pos = 0; + info->fprintf_func = (fprintf_ftype) objdump_sprintf; + info->stream = &sfile; + info->bytes_per_line = 0; + info->bytes_per_chunk = 0; + info->flags = 0; + + if (info->disassembler_needs_relocs + && *relppp < relppend) + { + bfd_signed_vma distance_to_rel; + + distance_to_rel = (**relppp)->address + - (rel_offset + addr_offset); + + /* Check to see if the current reloc is associated with + the instruction that we are about to disassemble. */ + if (distance_to_rel == 0 + /* FIXME: This is wrong. We are trying to catch + relocs that are addressed part way through the + current instruction, as might happen with a packed + VLIW instruction. Unfortunately we do not know the + length of the current instruction since we have not + disassembled it yet. Instead we take a guess based + upon the length of the previous instruction. The + proper solution is to have a new target-specific + disassembler function which just returns the length + of an instruction at a given address without trying + to display its disassembly. */ + || (distance_to_rel > 0 + && distance_to_rel < (bfd_signed_vma) (previous_octets/ opb))) + { + info->flags = INSN_HAS_RELOC; + aux->reloc = **relppp; + } + else + aux->reloc = NULL; + } + + 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.pos) + printf ("%s\n", 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 if (sfile.pos) + printf ("%s", 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; + } + + while ((*relppp) < relppend + && (**relppp)->address < rel_offset + addr_offset + octets / opb) + { + if (dump_reloc_info || dump_dynamic_reloc_info) + { + arelent *q; + + q = **relppp; + + if (wide_output) + putchar ('\t'); + else + printf ("\t\t\t"); + + objdump_print_value (section->vma - rel_offset + q->address, + info, TRUE); + + if (q->howto == NULL) + printf (": *unknown*\t"); + else if (q->howto->name) + printf (": %s\t", q->howto->name); + else + printf (": %d\t", q->howto->type); + + 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; + } + + free (sfile.buffer); +} + +static void +disassemble_section (bfd *abfd, asection *section, void *info) +{ + struct disassemble_info * pinfo = (struct disassemble_info *) info; + struct objdump_disasm_info * paux; + unsigned int opb = pinfo->octets_per_byte; + bfd_byte * data = NULL; + bfd_size_type datasize = 0; + arelent ** rel_pp = NULL; + arelent ** rel_ppstart = NULL; + arelent ** rel_ppend; + unsigned long stop_offset; + asymbol * sym = NULL; + long place = 0; + long rel_count; + bfd_vma rel_offset; + unsigned long addr_offset; + + /* Sections that do not contain machine + code are not normally disassembled. */ + if (! disassemble_all + && only == NULL + && ((section->flags & (SEC_CODE | SEC_HAS_CONTENTS)) + != (SEC_CODE | SEC_HAS_CONTENTS))) + return; + + if (! process_section_p (section)) + return; + + datasize = bfd_get_section_size (section); + if (datasize == 0) + return; + + /* Decide which set of relocs to use. Load them if necessary. */ + paux = (struct objdump_disasm_info *) pinfo->application_data; + if (paux->dynrelbuf) + { + rel_pp = paux->dynrelbuf; + rel_count = paux->dynrelcount; + /* Dynamic reloc addresses are absolute, non-dynamic are section + relative. REL_OFFSET specifies the reloc address corresponding + to the start of this section. */ + rel_offset = section->vma; + } + else + { + rel_count = 0; + rel_pp = NULL; + rel_offset = 0; + + if ((section->flags & SEC_RELOC) != 0 + && (dump_reloc_info || pinfo->disassembler_needs_relocs)) + { + long relsize; + + relsize = bfd_get_reloc_upper_bound (abfd, section); + if (relsize < 0) + bfd_fatal (bfd_get_filename (abfd)); + + if (relsize > 0) + { + rel_ppstart = rel_pp = xmalloc (relsize); + rel_count = bfd_canonicalize_reloc (abfd, section, rel_pp, syms); + if (rel_count < 0) + bfd_fatal (bfd_get_filename (abfd)); + + /* Sort the relocs by address. */ + qsort (rel_pp, rel_count, sizeof (arelent *), compare_relocs); + } + } + + } + rel_ppend = rel_pp + rel_count; + + data = xmalloc (datasize); + + bfd_get_section_contents (abfd, section, data, 0, datasize); + + paux->sec = section; + pinfo->buffer = data; + pinfo->buffer_vma = section->vma; + pinfo->buffer_length = datasize; + pinfo->section = section; + + if (start_address == (bfd_vma) -1 + || start_address < pinfo->buffer_vma) + addr_offset = 0; + else + addr_offset = start_address - pinfo->buffer_vma; + + if (stop_address == (bfd_vma) -1) + stop_offset = datasize / opb; + else + { + if (stop_address < pinfo->buffer_vma) + stop_offset = 0; + else + stop_offset = stop_address - pinfo->buffer_vma; + if (stop_offset > pinfo->buffer_length / opb) + stop_offset = pinfo->buffer_length / opb; + } + + /* Skip over the relocs belonging to addresses below the + start address. */ + while (rel_pp < rel_ppend + && (*rel_pp)->address < rel_offset + addr_offset) + ++rel_pp; + + printf (_("Disassembly of section %s:\n"), section->name); + + /* Find the nearest symbol forwards from our current position. */ + paux->require_sec = TRUE; + sym = find_symbol_for_address (section->vma + addr_offset, info, &place); + paux->require_sec = FALSE; + + /* Disassemble a block of instructions up to the address associated with + the symbol we have just found. Then print the symbol and find the + next symbol on. Repeat until we have disassembled the entire section + or we have reached the end of the address range we are interested in. */ + while (addr_offset < stop_offset) + { + bfd_vma addr; + asymbol *nextsym; + unsigned long nextstop_offset; + bfd_boolean insns; + + addr = section->vma + addr_offset; + + if (sym != NULL && bfd_asymbol_value (sym) <= addr) + { + int x; + + for (x = place; + (x < sorted_symcount + && (bfd_asymbol_value (sorted_syms[x]) <= addr)); + ++x) + continue; + + pinfo->symbols = sorted_syms + place; + pinfo->num_symbols = x - place; + } + else + { + pinfo->symbols = NULL; + pinfo->num_symbols = 0; + } + + if (! prefix_addresses) + { + pinfo->fprintf_func (pinfo->stream, "\n"); + objdump_print_addr_with_sym (abfd, section, sym, addr, + pinfo, FALSE); + pinfo->fprintf_func (pinfo->stream, ":\n"); + } + + if (sym != NULL && bfd_asymbol_value (sym) > addr) + nextsym = sym; + else if (sym == NULL) + nextsym = NULL; + else + { +#define is_valid_next_sym(SYM) \ + ((SYM)->section == section \ + && (bfd_asymbol_value (SYM) > bfd_asymbol_value (sym)) \ + && pinfo->symbol_is_valid (SYM, pinfo)) + + /* 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 + && ! is_valid_next_sym (sorted_syms [place])) + ++place; + + if (place >= sorted_symcount) + nextsym = NULL; + else + nextsym = sorted_syms[place]; + } + + if (sym != NULL && bfd_asymbol_value (sym) > addr) + nextstop_offset = bfd_asymbol_value (sym) - section->vma; + 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) > addr + || ((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 (pinfo, paux->disassemble_fn, insns, data, + addr_offset, nextstop_offset, + rel_offset, &rel_pp, rel_ppend); + + addr_offset = nextstop_offset; + sym = nextsym; + } + + free (data); + + if (rel_ppstart != NULL) + free (rel_ppstart); +} + +/* Disassemble the contents of an object file. */ + +static void +disassemble_data (bfd *abfd) +{ + struct disassemble_info disasm_info; + struct objdump_disasm_info aux; + long i; + + 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_symcount = symcount ? symcount : dynsymcount; + sorted_syms = xmalloc ((sorted_symcount + synthcount) * sizeof (asymbol *)); + memcpy (sorted_syms, symcount ? syms : dynsyms, + sorted_symcount * sizeof (asymbol *)); + + sorted_symcount = remove_useless_symbols (sorted_syms, sorted_symcount); + + for (i = 0; i < synthcount; ++i) + { + sorted_syms[sorted_symcount] = synthsyms + i; + ++sorted_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_ftype) fprintf); + + disasm_info.application_data = (void *) &aux; + aux.abfd = abfd; + aux.require_sec = FALSE; + aux.dynrelbuf = NULL; + aux.dynrelcount = 0; + aux.reloc = NULL; + + disasm_info.print_address_func = objdump_print_address; + disasm_info.symbol_at_address_func = objdump_symbol_at_address; + + if (machine != 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 = xmalloc (sizeof (struct bfd_target)); + memcpy (xvec, abfd->xvec, sizeof (struct bfd_target)); + xvec->byteorder = endian; + abfd->xvec = xvec; + } + + /* Use libopcodes to locate a suitable disassembler. */ + aux.disassemble_fn = disassembler (abfd); + if (!aux.disassemble_fn) + { + non_fatal (_("Can't disassemble for architecture %s\n"), + bfd_printable_arch_mach (bfd_get_arch (abfd), 0)); + exit_status = 1; + return; + } + + 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 = bfd_octets_per_byte (abfd); + disasm_info.skip_zeroes = DEFAULT_SKIP_ZEROES; + disasm_info.skip_zeroes_at_end = DEFAULT_SKIP_ZEROES_AT_END; + disasm_info.disassembler_needs_relocs = FALSE; + + 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; + + /* Allow the target to customize the info structure. */ + disassemble_init_for_target (& disasm_info); + + /* Pre-load the dynamic relocs if we are going + to be dumping them along with the disassembly. */ + if (dump_dynamic_reloc_info) + { + long relsize = bfd_get_dynamic_reloc_upper_bound (abfd); + + if (relsize < 0) + bfd_fatal (bfd_get_filename (abfd)); + + if (relsize > 0) + { + aux.dynrelbuf = xmalloc (relsize); + aux.dynrelcount = bfd_canonicalize_dynamic_reloc (abfd, + aux.dynrelbuf, + dynsyms); + if (aux.dynrelcount < 0) + bfd_fatal (bfd_get_filename (abfd)); + + /* Sort the relocs by address. */ + qsort (aux.dynrelbuf, aux.dynrelcount, sizeof (arelent *), + compare_relocs); + } + } + + bfd_map_over_sections (abfd, disassemble_section, & disasm_info); + + if (aux.dynrelbuf != NULL) + free (aux.dynrelbuf); + free (sorted_syms); +} + +int +load_debug_section (enum dwarf_section_display_enum debug, void *file) +{ + struct dwarf_section *section = &debug_displays [debug].section; + bfd *abfd = file; + asection *sec; + bfd_boolean ret; + + /* If it is already loaded, do nothing. */ + if (section->start != NULL) + return 1; + + /* Locate the debug section. */ + sec = bfd_get_section_by_name (abfd, section->name); + if (sec == NULL) + return 0; + + section->address = bfd_get_section_vma (abfd, sec); + section->size = bfd_get_section_size (sec); + section->start = xmalloc (section->size); + + if (is_relocatable && debug_displays [debug].relocate) + ret = bfd_simple_get_relocated_section_contents (abfd, + sec, + section->start, + syms) != NULL; + else + ret = bfd_get_section_contents (abfd, sec, section->start, 0, + section->size); + + if (!ret) + { + free_debug_section (debug); + printf (_("\nCan't get contents for section '%s'.\n"), + section->name); + } + + return ret; +} + +void +free_debug_section (enum dwarf_section_display_enum debug) +{ + struct dwarf_section *section = &debug_displays [debug].section; + + if (section->start == NULL) + return; + + free ((char *) section->start); + section->start = NULL; + section->address = 0; + section->size = 0; +} + +static void +dump_dwarf_section (bfd *abfd, asection *section, + void *arg ATTRIBUTE_UNUSED) +{ + const char *name = bfd_get_section_name (abfd, section); + const char *match; + enum dwarf_section_display_enum i; + + if (strncmp (name, ".gnu.linkonce.wi.", 17) == 0) + match = ".debug_info"; + else + match = name; + + for (i = 0; i < max; i++) + if (strcmp (debug_displays[i].section.name, match) == 0) + { + if (!debug_displays[i].eh_frame) + { + struct dwarf_section *sec = &debug_displays [i].section; + + if (load_debug_section (i, abfd)) + { + debug_displays[i].display (sec, abfd); + + if (i != info && i != abbrev) + free_debug_section (i); + } + } + break; + } +} + +static const char *mach_o_dwarf_sections [] = { + "LC_SEGMENT.__DWARFA.__debug_abbrev", /* .debug_abbrev */ + "LC_SEGMENT.__DWARFA.__debug_aranges", /* .debug_aranges */ + "LC_SEGMENT.__DWARFA.__debug_frame", /* .debug_frame */ + "LC_SEGMENT.__DWARFA.__debug_info", /* .debug_info */ + "LC_SEGMENT.__DWARFA.__debug_line", /* .debug_line */ + "LC_SEGMENT.__DWARFA.__debug_pubnames", /* .debug_pubnames */ + ".eh_frame", /* .eh_frame */ + "LC_SEGMENT.__DWARFA.__debug_macinfo", /* .debug_macinfo */ + "LC_SEGMENT.__DWARFA.__debug_str", /* .debug_str */ + "LC_SEGMENT.__DWARFA.__debug_loc", /* .debug_loc */ + "LC_SEGMENT.__DWARFA.__debug_pubtypes", /* .debug_pubtypes */ + "LC_SEGMENT.__DWARFA.__debug_ranges", /* .debug_ranges */ + "LC_SEGMENT.__DWARFA.__debug_static_func", /* .debug_static_func */ + "LC_SEGMENT.__DWARFA.__debug_static_vars", /* .debug_static_vars */ + "LC_SEGMENT.__DWARFA.__debug_types", /* .debug_types */ + "LC_SEGMENT.__DWARFA.__debug_weaknames" /* .debug_weaknames */ +}; + +static const char *generic_dwarf_sections [max]; + +static void +check_mach_o_dwarf (bfd *abfd) +{ + static enum bfd_flavour old_flavour = bfd_target_unknown_flavour; + enum bfd_flavour current_flavour = bfd_get_flavour (abfd); + enum dwarf_section_display_enum i; + + if (generic_dwarf_sections [0] == NULL) + for (i = 0; i < max; i++) + generic_dwarf_sections [i] = debug_displays[i].section.name; + + if (old_flavour != current_flavour) + { + if (current_flavour == bfd_target_mach_o_flavour) + for (i = 0; i < max; i++) + debug_displays[i].section.name = mach_o_dwarf_sections [i]; + else if (old_flavour == bfd_target_mach_o_flavour) + for (i = 0; i < max; i++) + debug_displays[i].section.name = generic_dwarf_sections [i]; + + old_flavour = current_flavour; + } +} + +/* Dump the dwarf debugging information. */ + +static void +dump_dwarf (bfd *abfd) +{ + is_relocatable = ((abfd->flags & (HAS_RELOC | EXEC_P | DYNAMIC)) + == HAS_RELOC); + + /* FIXME: bfd_get_arch_size may return -1. We assume that 64bit + targets will return 64. */ + eh_addr_size = bfd_get_arch_size (abfd) == 64 ? 8 : 4; + + if (bfd_big_endian (abfd)) + byte_get = byte_get_big_endian; + else if (bfd_little_endian (abfd)) + byte_get = byte_get_little_endian; + else + abort (); + + check_mach_o_dwarf (abfd); + + bfd_map_over_sections (abfd, dump_dwarf_section, NULL); + + free_debug_memory (); +} + +/* Read ABFD's stabs section STABSECT_NAME, and return a pointer to + it. Return NULL on failure. */ + +static char * +read_section_stabs (bfd *abfd, const char *sect_name, bfd_size_type *size_ptr) +{ + asection *stabsect; + bfd_size_type size; + char *contents; + + stabsect = bfd_get_section_by_name (abfd, sect_name); + if (stabsect == NULL) + { + printf (_("No %s section present\n\n"), sect_name); + return FALSE; + } + + size = bfd_section_size (abfd, stabsect); + contents = xmalloc (size); + + if (! bfd_get_section_contents (abfd, stabsect, contents, 0, size)) + { + non_fatal (_("Reading %s section of %s failed: %s"), + sect_name, bfd_get_filename (abfd), + bfd_errmsg (bfd_get_error ())); + free (contents); + exit_status = 1; + return NULL; + } + + *size_ptr = size; + + return contents; +} + +/* 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 (bfd *abfd, + const char *stabsect_name, + unsigned *string_offset_ptr) +{ + int i; + unsigned file_string_table_offset = 0; + unsigned next_file_string_table_offset = *string_offset_ptr; + 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"); + *string_offset_ptr = next_file_string_table_offset; +} + +typedef struct +{ + const char * section_name; + const char * string_section_name; + unsigned string_offset; +} +stab_section_names; + +static void +find_stabs_section (bfd *abfd, asection *section, void *names) +{ + int len; + stab_section_names * sought = (stab_section_names *) names; + + /* Check for section names for which stabsect_name is a prefix, to + handle .stab.N, etc. */ + len = strlen (sought->section_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 (sought->section_name, section->name, len) == 0 + && (section->name[len] == 0 + || (section->name[len] == '.' && ISDIGIT (section->name[len + 1])))) + { + if (strtab == NULL) + strtab = read_section_stabs (abfd, sought->string_section_name, + &stabstr_size); + + if (strtab) + { + stabs = (bfd_byte *) read_section_stabs (abfd, section->name, + &stab_size); + if (stabs) + print_section_stabs (abfd, section->name, &sought->string_offset); + } + } +} + +static void +dump_stabs_section (bfd *abfd, char *stabsect_name, char *strsect_name) +{ + stab_section_names s; + + s.section_name = stabsect_name; + s.string_section_name = strsect_name; + s.string_offset = 0; + + bfd_map_over_sections (abfd, find_stabs_section, & s); + + free (strtab); + strtab = NULL; +} + +/* Dump the any sections containing stabs debugging information. */ + +static void +dump_stabs (bfd *abfd) +{ + dump_stabs_section (abfd, ".stab", ".stabstr"); + dump_stabs_section (abfd, ".stab.excl", ".stab.exclstr"); + dump_stabs_section (abfd, ".stab.index", ".stab.indexstr"); + dump_stabs_section (abfd, "$GDB_SYMBOLS$", "$GDB_STRINGS$"); +} + +static void +dump_bfd_header (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 (bfd *abfd) +{ + bfd_print_private_bfd_data (abfd, stdout); +} + + +/* Display a section in hexadecimal format with associated characters. + Each line prefixed by the zero padded address. */ + +static void +dump_section (bfd *abfd, asection *section, void *dummy ATTRIBUTE_UNUSED) +{ + bfd_byte *data = 0; + bfd_size_type datasize; + bfd_size_type addr_offset; + bfd_size_type start_offset; + bfd_size_type stop_offset; + unsigned int opb = bfd_octets_per_byte (abfd); + /* Bytes per line. */ + const int onaline = 16; + char buf[64]; + int count; + int width; + + if ((section->flags & SEC_HAS_CONTENTS) == 0) + return; + + if (! process_section_p (section)) + return; + + if ((datasize = bfd_section_size (abfd, section)) == 0) + return; + + printf (_("Contents of section %s:\n"), section->name); + + data = xmalloc (datasize); + + bfd_get_section_contents (abfd, section, data, 0, datasize); + + /* Compute the address range to display. */ + 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 = datasize / opb; + else + { + if (stop_address < section->vma) + stop_offset = 0; + else + stop_offset = stop_address - section->vma; + + if (stop_offset > datasize / opb) + stop_offset = datasize / 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 ((size_t) 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); +} + +/* Actually display the various requested regions. */ + +static void +dump_data (bfd *abfd) +{ + bfd_map_over_sections (abfd, dump_section, NULL); +} + +/* Should perhaps share code and display with nm? */ + +static void +dump_symbols (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++) + { + bfd *cur_bfd; + + if (*current == NULL) + printf (_("no information for symbol number %ld\n"), count); + + else if ((cur_bfd = bfd_asymbol_bfd (*current)) == NULL) + printf (_("could not determine the type of symbol number %ld\n"), + count); + + else if (process_section_p ((* current)->section) + && (dump_special_syms + || !bfd_is_target_special_symbol (cur_bfd, *current))) + { + const char *name = (*current)->name; + + if (do_demangle && name != NULL && *name != '\0') + { + char *alloc; + + /* 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; + free (alloc); + } + else + bfd_print_symbol (cur_bfd, stdout, *current, + bfd_print_symbol_all); + printf ("\n"); + } + + current++; + } + printf ("\n\n"); +} + +static void +dump_reloc_set (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 != 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; + } + + bfd_printf_vma (abfd, q->address); + if (q->howto == NULL) + printf (" *unknown* "); + else if (q->howto->name) + printf (" %-16s ", q->howto->name); + else + printf (" %-16d ", q->howto->type); + if (sym_name) + objdump_print_symname (abfd, NULL, *q->sym_ptr_ptr); + else + { + if (section_name == NULL) + section_name = "*unknown*"; + printf ("[%s]", section_name); + } + + if (q->addend) + { + printf ("+0x"); + bfd_printf_vma (abfd, q->addend); + } + + printf ("\n"); + } +} + +static void +dump_relocs_in_section (bfd *abfd, + asection *section, + void *dummy ATTRIBUTE_UNUSED) +{ + arelent **relpp; + long relcount; + long relsize; + + if ( bfd_is_abs_section (section) + || bfd_is_und_section (section) + || bfd_is_com_section (section) + || (! process_section_p (section)) + || ((section->flags & SEC_RELOC) == 0)) + return; + + relsize = bfd_get_reloc_upper_bound (abfd, section); + if (relsize < 0) + bfd_fatal (bfd_get_filename (abfd)); + + printf ("RELOCATION RECORDS FOR [%s]:", section->name); + + if (relsize == 0) + { + printf (" (none)\n\n"); + return; + } + + relpp = xmalloc (relsize); + relcount = bfd_canonicalize_reloc (abfd, section, 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, section, relpp, relcount); + printf ("\n\n"); + } + free (relpp); +} + +static void +dump_relocs (bfd *abfd) +{ + bfd_map_over_sections (abfd, dump_relocs_in_section, NULL); +} + +static void +dump_dynamic_relocs (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 = 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, NULL, relpp, relcount); + printf ("\n\n"); + } + free (relpp); + } +} + +/* Creates a table of paths, to search for source files. */ + +static void +add_include_path (const char *path) +{ + if (path[0] == 0) + return; + include_path_count++; + include_paths = xrealloc (include_paths, + include_path_count * sizeof (*include_paths)); +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + if (path[1] == ':' && path[2] == 0) + path = concat (path, ".", (const char *) 0); +#endif + include_paths[include_path_count - 1] = path; +} + +static void +adjust_addresses (bfd *abfd ATTRIBUTE_UNUSED, + asection *section, + void *arg) +{ + if ((section->flags & SEC_DEBUGGING) == 0) + { + bfd_boolean *has_reloc_p = (bfd_boolean *) arg; + section->vma += adjust_section_vma; + if (*has_reloc_p) + section->lma += adjust_section_vma; + } +} + +/* Dump selected contents of ABFD. */ + +static void +dump_bfd (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) + { + bfd_boolean has_reloc = (abfd->flags & HAS_RELOC); + bfd_map_over_sections (abfd, adjust_addresses, &has_reloc); + } + + if (! dump_debugging_tags) + 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); + if (! dump_debugging_tags) + putchar ('\n'); + if (dump_section_headers) + dump_headers (abfd); + + if (dump_symtab + || dump_reloc_info + || disassemble + || dump_debugging + || dump_dwarf_section_info) + syms = slurp_symtab (abfd); + if (dump_dynamic_symtab || dump_dynamic_reloc_info + || (disassemble && bfd_get_dynamic_symtab_upper_bound (abfd) > 0)) + dynsyms = slurp_dynamic_symtab (abfd); + if (disassemble) + { + synthcount = bfd_get_synthetic_symtab (abfd, symcount, syms, + dynsymcount, dynsyms, &synthsyms); + if (synthcount < 0) + synthcount = 0; + } + + if (dump_symtab) + dump_symbols (abfd, FALSE); + if (dump_dynamic_symtab) + dump_symbols (abfd, TRUE); + if (dump_dwarf_section_info) + dump_dwarf (abfd); + if (dump_stab_section_info) + dump_stabs (abfd); + if (dump_reloc_info && ! disassemble) + dump_relocs (abfd); + if (dump_dynamic_reloc_info && ! disassemble) + dump_dynamic_relocs (abfd); + if (dump_section_contents) + dump_data (abfd); + if (disassemble) + disassemble_data (abfd); + + if (dump_debugging) + { + void *dhandle; + + dhandle = read_debugging_info (abfd, syms, symcount); + if (dhandle != NULL) + { + if (! print_debugging_info (stdout, dhandle, abfd, syms, demangle, + dump_debugging_tags ? TRUE : FALSE)) + { + 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; + } + + if (synthsyms) + { + free (synthsyms); + synthsyms = NULL; + } + + symcount = 0; + dynsymcount = 0; + synthcount = 0; +} + +static void +display_bfd (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 (char *filename, char *target) +{ + bfd *file; + bfd *arfile = NULL; + + if (get_file_size (filename) < 1) + return; + + file = bfd_openr (filename, target); + if (file == NULL) + { + nonfatal (filename); + return; + } + + /* If the file is an archive, process all of its elements. */ + 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); +} + +int +main (int argc, char **argv) +{ + int c; + char *target = default_target; + bfd_boolean seenflag = FALSE; + +#if defined (HAVE_SETLOCALE) +#if defined (HAVE_LC_MESSAGES) + setlocale (LC_MESSAGES, ""); +#endif + setlocale (LC_CTYPE, ""); +#endif + + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + program_name = *argv; + xmalloc_set_program_name (program_name); + + START_PROGRESS (program_name, 0); + + expandargv (&argc, &argv); + + bfd_init (); + set_default_bfd_target (); + + while ((c = getopt_long (argc, argv, "pib:m:M:VvCdDlfaHhrRtTxsSI:j:wE:zgeGW", + long_options, (int *) 0)) + != EOF) + { + switch (c) + { + case 0: + break; /* We've been given a long option. */ + case 'm': + machine = optarg; + break; + case 'M': + if (disassembler_options) + /* Ignore potential memory leak for now. */ + disassembler_options = concat (disassembler_options, ",", + optarg, NULL); + else + disassembler_options = optarg; + break; + case 'j': + if (only_used == only_size) + { + only_size += 8; + only = xrealloc (only, only_size * sizeof (char *)); + } + only [only_used++] = 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 'I': + add_include_path (optarg); + 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 'e': + dump_debugging = 1; + dump_debugging_tags = 1; + do_demangle = TRUE; + seenflag = TRUE; + break; + case 'W': + dump_dwarf_section_info = TRUE; + seenflag = TRUE; + do_debug_info = 1; + do_debug_abbrevs = 1; + do_debug_lines = 1; + do_debug_pubnames = 1; + do_debug_aranges = 1; + do_debug_ranges = 1; + do_debug_frames = 1; + do_debug_macinfo = 1; + do_debug_str = 1; + do_debug_loc = 1; + 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.17/binutils/prdbg.c b/contrib/binutils-2.17/binutils/prdbg.c new file mode 100644 index 0000000000..87a49341b0 --- /dev/null +++ b/contrib/binutils-2.17/binutils/prdbg.c @@ -0,0 +1,2795 @@ +/* prdbg.c -- Print out generic debugging information. + Copyright 1995, 1996, 1999, 2002, 2003, 2004 + Free Software Foundation, Inc. + Written by Ian Lance Taylor . + Tags style generation written by Salvador E. Tropea . + + 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 following are used only by the tags code (tg_). */ + /* Name of the file we are using. */ + char *filename; + /* The BFD. */ + bfd *abfd; + /* The symbols table for this BFD. */ + asymbol **syms; + /* Pointer to a function to demangle symbols. */ + char *(*demangler) (bfd *, const char *); +}; + +/* 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; + /* The following are used only by the tags code (tg_). */ + /* Type for the container (struct, union, class, union class). */ + const char *flavor; + /* A comma separated list of parent classes. */ + char *parents; + /* How many parents contains parents. */ + int num_parents; +}; + +static void indent (struct pr_handle *); +static bfd_boolean push_type (struct pr_handle *, const char *); +static bfd_boolean prepend_type (struct pr_handle *, const char *); +static bfd_boolean append_type (struct pr_handle *, const char *); +static bfd_boolean substitute_type (struct pr_handle *, const char *); +static bfd_boolean indent_type (struct pr_handle *); +static char *pop_type (struct pr_handle *); +static void print_vma (bfd_vma, char *, bfd_boolean, bfd_boolean); +static bfd_boolean pr_fix_visibility + (struct pr_handle *, enum debug_visibility); +static bfd_boolean pr_start_compilation_unit (void *, const char *); +static bfd_boolean pr_start_source (void *, const char *); +static bfd_boolean pr_empty_type (void *); +static bfd_boolean pr_void_type (void *); +static bfd_boolean pr_int_type (void *, unsigned int, bfd_boolean); +static bfd_boolean pr_float_type (void *, unsigned int); +static bfd_boolean pr_complex_type (void *, unsigned int); +static bfd_boolean pr_bool_type (void *, unsigned int); +static bfd_boolean pr_enum_type + (void *, const char *, const char **, bfd_signed_vma *); +static bfd_boolean pr_pointer_type (void *); +static bfd_boolean pr_function_type (void *, int, bfd_boolean); +static bfd_boolean pr_reference_type (void *); +static bfd_boolean pr_range_type (void *, bfd_signed_vma, bfd_signed_vma); +static bfd_boolean pr_array_type + (void *, bfd_signed_vma, bfd_signed_vma, bfd_boolean); +static bfd_boolean pr_set_type (void *, bfd_boolean); +static bfd_boolean pr_offset_type (void *); +static bfd_boolean pr_method_type (void *, bfd_boolean, int, bfd_boolean); +static bfd_boolean pr_const_type (void *); +static bfd_boolean pr_volatile_type (void *); +static bfd_boolean pr_start_struct_type + (void *, const char *, unsigned int, bfd_boolean, unsigned int); +static bfd_boolean pr_struct_field + (void *, const char *, bfd_vma, bfd_vma, enum debug_visibility); +static bfd_boolean pr_end_struct_type (void *); +static bfd_boolean pr_start_class_type + (void *, const char *, unsigned int, bfd_boolean, unsigned int, + bfd_boolean, bfd_boolean); +static bfd_boolean pr_class_static_member + (void *, const char *, const char *, enum debug_visibility); +static bfd_boolean pr_class_baseclass + (void *, bfd_vma, bfd_boolean, enum debug_visibility); +static bfd_boolean pr_class_start_method (void *, const char *); +static bfd_boolean pr_class_method_variant + (void *, const char *, enum debug_visibility, bfd_boolean, bfd_boolean, + bfd_vma, bfd_boolean); +static bfd_boolean pr_class_static_method_variant + (void *, const char *, enum debug_visibility, bfd_boolean, bfd_boolean); +static bfd_boolean pr_class_end_method (void *); +static bfd_boolean pr_end_class_type (void *); +static bfd_boolean pr_typedef_type (void *, const char *); +static bfd_boolean pr_tag_type + (void *, const char *, unsigned int, enum debug_type_kind); +static bfd_boolean pr_typdef (void *, const char *); +static bfd_boolean pr_tag (void *, const char *); +static bfd_boolean pr_int_constant (void *, const char *, bfd_vma); +static bfd_boolean pr_float_constant (void *, const char *, double); +static bfd_boolean pr_typed_constant (void *, const char *, bfd_vma); +static bfd_boolean pr_variable + (void *, const char *, enum debug_var_kind, bfd_vma); +static bfd_boolean pr_start_function (void *, const char *, bfd_boolean); +static bfd_boolean pr_function_parameter + (void *, const char *, enum debug_parm_kind, bfd_vma); +static bfd_boolean pr_start_block (void *, bfd_vma); +static bfd_boolean pr_end_block (void *, bfd_vma); +static bfd_boolean pr_end_function (void *); +static bfd_boolean pr_lineno (void *, const char *, unsigned long, bfd_vma); +static bfd_boolean append_parent (struct pr_handle *, const char *); +/* Only used by tg_ code. */ +static bfd_boolean tg_fix_visibility + (struct pr_handle *, enum debug_visibility); +static void find_address_in_section (bfd *, asection *, void *); +static void translate_addresses (bfd *, char *, FILE *, asymbol **); +static const char *visibility_name (enum debug_visibility); +/* Tags style replacements. */ +static bfd_boolean tg_start_compilation_unit (void *, const char *); +static bfd_boolean tg_start_source (void *, const char *); +static bfd_boolean tg_enum_type + (void *, const char *, const char **, bfd_signed_vma *); +static bfd_boolean tg_start_struct_type + (void *, const char *, unsigned int, bfd_boolean, unsigned int); +static bfd_boolean pr_struct_field + (void *, const char *, bfd_vma, bfd_vma, enum debug_visibility); +static bfd_boolean tg_struct_field + (void *, const char *, bfd_vma, bfd_vma, enum debug_visibility); +static bfd_boolean tg_struct_field + (void *, const char *, bfd_vma, bfd_vma, enum debug_visibility); +static bfd_boolean tg_end_struct_type (void *); +static bfd_boolean tg_start_class_type + (void *, const char *, unsigned int, bfd_boolean, unsigned int, bfd_boolean, bfd_boolean); +static bfd_boolean tg_class_static_member + (void *, const char *, const char *, enum debug_visibility); +static bfd_boolean tg_class_baseclass + (void *, bfd_vma, bfd_boolean, enum debug_visibility); +static bfd_boolean tg_class_method_variant + (void *, const char *, enum debug_visibility, bfd_boolean, bfd_boolean, bfd_vma, bfd_boolean); +static bfd_boolean tg_class_static_method_variant + (void *, const char *, enum debug_visibility, bfd_boolean, bfd_boolean); +static bfd_boolean tg_end_class_type (void *); +static bfd_boolean tg_tag_type + (void *, const char *, unsigned int, enum debug_type_kind); +static bfd_boolean tg_typdef (void *, const char *); +static bfd_boolean tg_tag (void *, const char *); +static bfd_boolean tg_int_constant (void *, const char *, bfd_vma); +static bfd_boolean tg_float_constant (void *, const char *, double); +static bfd_boolean tg_typed_constant (void *, const char *, bfd_vma); +static bfd_boolean tg_variable + (void *, const char *, enum debug_var_kind, bfd_vma); +static bfd_boolean tg_start_function (void *, const char *, bfd_boolean); +static bfd_boolean tg_function_parameter + (void *, const char *, enum debug_parm_kind, bfd_vma); +static bfd_boolean tg_start_block (void *, bfd_vma); +static bfd_boolean tg_end_block (void *, bfd_vma); +static bfd_boolean tg_lineno (void *, 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 +}; + +static const struct debug_write_fns tg_fns = +{ + tg_start_compilation_unit, + tg_start_source, + pr_empty_type, /* Same, push_type. */ + pr_void_type, /* Same, push_type. */ + pr_int_type, /* Same, push_type. */ + pr_float_type, /* Same, push_type. */ + pr_complex_type, /* Same, push_type. */ + pr_bool_type, /* Same, push_type. */ + tg_enum_type, + pr_pointer_type, /* Same, changes to pointer. */ + pr_function_type, /* Same, push_type. */ + pr_reference_type, /* Same, changes to reference. */ + pr_range_type, /* FIXME: What's that?. */ + pr_array_type, /* Same, push_type. */ + pr_set_type, /* FIXME: What's that?. */ + pr_offset_type, /* FIXME: What's that?. */ + pr_method_type, /* Same. */ + pr_const_type, /* Same, changes to const. */ + pr_volatile_type, /* Same, changes to volatile. */ + tg_start_struct_type, + tg_struct_field, + tg_end_struct_type, + tg_start_class_type, + tg_class_static_member, + tg_class_baseclass, + pr_class_start_method, /* Same, remembers that's a method. */ + tg_class_method_variant, + tg_class_static_method_variant, + pr_class_end_method, /* Same, forgets that's a method. */ + tg_end_class_type, + pr_typedef_type, /* Same, just push type. */ + tg_tag_type, + tg_typdef, + tg_tag, + tg_int_constant, /* Untested. */ + tg_float_constant, /* Untested. */ + tg_typed_constant, /* Untested. */ + tg_variable, + tg_start_function, + tg_function_parameter, + tg_start_block, + tg_end_block, + pr_end_function, /* Same, does nothing. */ + tg_lineno +}; + +/* Print out the generic debugging information recorded in dhandle. */ + +bfd_boolean +print_debugging_info (FILE *f, void *dhandle, bfd *abfd, asymbol **syms, + void *demangler, bfd_boolean as_tags) +{ + struct pr_handle info; + + info.f = f; + info.indent = 0; + info.stack = NULL; + info.parameter = 0; + info.filename = NULL; + info.abfd = abfd; + info.syms = syms; + info.demangler = demangler; + + if (as_tags) + { + fputs ("!_TAG_FILE_FORMAT\t2\t/extended format/\n", f); + fputs ("!_TAG_FILE_SORTED\t0\t/0=unsorted, 1=sorted/\n", f); + fputs ("!_TAG_PROGRAM_AUTHOR\tIan Lance Taylor, Salvador E. Tropea and others\t//\n", f); + fputs ("!_TAG_PROGRAM_NAME\tobjdump\t/From GNU binutils/\n", f); + } + + return as_tags ? debug_write (dhandle, &tg_fns, (void *) & info) + : debug_write (dhandle, &pr_fns, (void *) & info); +} + +/* Indent to the current indentation level. */ + +static void +indent (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 (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 (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 (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; +} + +/* Append a string to the parents on the top of the type stack. */ + +static bfd_boolean +append_parent (struct pr_handle *info, const char *s) +{ + unsigned int len; + + if (s == NULL) + return FALSE; + + assert (info->stack != NULL); + + len = info->stack->parents ? strlen (info->stack->parents) : 0; + info->stack->parents = (char *) xrealloc (info->stack->parents, + len + strlen (s) + 1); + strcpy (info->stack->parents + 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 (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 (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 (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 (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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *p) +{ + return pr_end_struct_type (p); +} + +/* Push a type on the stack using a typedef name. */ + +static bfd_boolean +pr_typedef_type (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *p ATTRIBUTE_UNUSED) +{ + return TRUE; +} + +/* Tags style generation functions start here. */ + +/* Variables for address to line translation. */ +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 (bfd *abfd, asection *section, void *data) +{ + bfd_vma vma; + bfd_size_type size; + asymbol **syms = (asymbol **) data; + + 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 (section); + if (pc >= vma + size) + return; + + found = bfd_find_nearest_line (abfd, section, syms, pc - vma, + &filename, &functionname, &line); +} + +static void +translate_addresses (bfd *abfd, char *addr_hex, FILE *f, asymbol **syms) +{ + pc = bfd_scan_vma (addr_hex, NULL, 16); + found = FALSE; + bfd_map_over_sections (abfd, find_address_in_section, syms); + + if (! found) + fprintf (f, "??"); + else + fprintf (f, "%u", line); +} + +/* Start a new compilation unit. */ + +static bfd_boolean +tg_start_compilation_unit (void * p, const char *filename ATTRIBUTE_UNUSED) +{ + struct pr_handle *info = (struct pr_handle *) p; + + fprintf (stderr, "New compilation unit: %s\n", filename); + + free (info->filename); + /* Should it be relative? best way to do it here?. */ + info->filename = strdup (filename); + + return TRUE; +} + +/* Start a source file within a compilation unit. */ + +static bfd_boolean +tg_start_source (void *p, const char *filename) +{ + struct pr_handle *info = (struct pr_handle *) p; + + free (info->filename); + /* Should it be relative? best way to do it here?. */ + info->filename = strdup (filename); + + return TRUE; +} + +/* Push an enum type onto the type stack. */ + +static bfd_boolean +tg_enum_type (void *p, const char *tag, const char **names, + bfd_signed_vma *values) +{ + struct pr_handle *info = (struct pr_handle *) p; + unsigned int i; + const char *name; + char ab[20]; + + if (! pr_enum_type (p, tag, names, values)) + return FALSE; + + name = tag ? tag : "unknown"; + /* Generate an entry for the enum. */ + if (tag) + fprintf (info->f, "%s\t%s\t0;\"\tkind:e\ttype:%s\n", tag, + info->filename, info->stack->type); + + /* Generate entries for the values. */ + if (names != NULL) + { + for (i = 0; names[i] != NULL; i++) + { + print_vma (values[i], ab, FALSE, FALSE); + fprintf (info->f, "%s\t%s\t0;\"\tkind:g\tenum:%s\tvalue:%s\n", + names[i], info->filename, name, ab); + } + } + + return TRUE; +} + +/* Start accumulating a struct type. */ + +static bfd_boolean +tg_start_struct_type (void *p, const char *tag, unsigned int id, + bfd_boolean structp, + unsigned int size ATTRIBUTE_UNUSED) +{ + struct pr_handle *info = (struct pr_handle *) p; + const char *name; + char idbuf[20]; + + if (tag != NULL) + name = tag; + else + { + name = idbuf; + sprintf (idbuf, "%%anon%u", id); + } + + if (! push_type (info, name)) + return FALSE; + + info->stack->flavor = structp ? "struct" : "union"; + + fprintf (info->f, "%s\t%s\t0;\"\tkind:%c\n", name, info->filename, + info->stack->flavor[0]); + + info->stack->visibility = DEBUG_VISIBILITY_PUBLIC; + + return indent_type (info); +} + +/* Output the visibility of a field in a struct. */ + +static bfd_boolean +tg_fix_visibility (struct pr_handle *info, enum debug_visibility visibility) +{ + assert (info->stack != NULL); + + if (info->stack->visibility == visibility) + return TRUE; + + assert (info->stack->visibility != DEBUG_VISIBILITY_IGNORE); + + info->stack->visibility = visibility; + + return TRUE; +} + +/* Add a field to a struct type. */ + +static bfd_boolean +tg_struct_field (void *p, const char *name, bfd_vma bitpos ATTRIBUTE_UNUSED, + bfd_vma bitsize ATTRIBUTE_UNUSED, + enum debug_visibility visibility) +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + + t = pop_type (info); + if (t == NULL) + return FALSE; + + if (! tg_fix_visibility (info, visibility)) + return FALSE; + + /* It happens, a bug? */ + if (! name[0]) + return TRUE; + + fprintf (info->f, "%s\t%s\t0;\"\tkind:m\ttype:%s\t%s:%s\taccess:%s\n", + name, info->filename, t, info->stack->flavor, info->stack->type, + visibility_name (visibility)); + + return TRUE; +} + +/* Finish a struct type. */ + +static bfd_boolean +tg_end_struct_type (void *p ATTRIBUTE_UNUSED) +{ + struct pr_handle *info = (struct pr_handle *) p; + assert (info->stack != NULL); + + return TRUE; +} + +/* Start a class type. */ + +static bfd_boolean +tg_start_class_type (void *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; + const char *name; + + info->indent += 2; + + if (vptr && ! ownvptr) + { + tv = pop_type (info); + if (tv == NULL) + return FALSE; + } + + if (tag != NULL) + name = tag; + else + { + char idbuf[20]; + + sprintf (idbuf, "%%anon%u", id); + name = idbuf; + } + + if (! push_type (info, name)) + return FALSE; + + info->stack->flavor = structp ? "class" : "union class"; + info->stack->parents = NULL; + info->stack->num_parents = 0; + + if (size != 0 || vptr || ownvptr || tag != NULL) + { + 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; + } + } + } + + info->stack->visibility = DEBUG_VISIBILITY_PRIVATE; + + return TRUE; +} + +/* Add a static member to a class. */ + +static bfd_boolean +tg_class_static_member (void *p, const char *name, + const char *physname ATTRIBUTE_UNUSED, + enum debug_visibility visibility) +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + int len_var, len_class; + char *full_name; + + len_var = strlen (name); + len_class = strlen (info->stack->next->type); + full_name = (char *) xmalloc (len_var + len_class + 3); + if (! full_name) + return FALSE; + memcpy (full_name, info->stack->next->type, len_class); + memcpy (full_name + len_class, "::", 2); + memcpy (full_name + len_class + 2, name, len_var + 1); + + if (! substitute_type (info, full_name)) + return FALSE; + + if (! prepend_type (info, "static ")) + return FALSE; + + t = pop_type (info); + if (t == NULL) + return FALSE; + + if (! tg_fix_visibility (info, visibility)) + return FALSE; + + fprintf (info->f, "%s\t%s\t0;\"\tkind:x\ttype:%s\tclass:%s\taccess:%s\n", + name, info->filename, t, info->stack->type, + visibility_name (visibility)); + free (t); + free (full_name); + + return TRUE; +} + +/* Add a base class to a class. */ + +static bfd_boolean +tg_class_baseclass (void *p, bfd_vma bitpos ATTRIBUTE_UNUSED, + bfd_boolean virtual, enum debug_visibility visibility) +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + const char *prefix; + + assert (info->stack != NULL && info->stack->next != NULL); + + 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; + + t = pop_type (info); + if (t == NULL) + return FALSE; + + if (info->stack->num_parents && ! append_parent (info, ", ")) + return FALSE; + + if (! append_parent (info, t)) + return FALSE; + info->stack->num_parents++; + + free (t); + + return TRUE; +} + +/* Add a variant to a method. */ + +static bfd_boolean +tg_class_method_variant (void *p, const char *physname ATTRIBUTE_UNUSED, + enum debug_visibility visibility, + bfd_boolean constp, bfd_boolean volatilep, + bfd_vma voffset ATTRIBUTE_UNUSED, + bfd_boolean context) +{ + struct pr_handle *info = (struct pr_handle *) p; + char *method_type; + char *context_type; + char *method_name; + + 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; + } + + method_name = strdup (context ? info->stack->next->next->method + : info->stack->next->method); + + /* Stick the name of the method into its type. */ + if (! substitute_type (info, method_name)) + 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 (! tg_fix_visibility (info, visibility)) + return FALSE; + + fprintf (info->f, "%s\t%s\t0;\"\tkind:p\ttype:%s\tclass:%s\n", + method_name, info->filename, method_type, info->stack->type); + free (method_type); + free (method_name); + free (context_type); + + return TRUE; +} + +/* Add a static variant to a method. */ + +static bfd_boolean +tg_class_static_method_variant (void *p, + const char *physname ATTRIBUTE_UNUSED, + enum debug_visibility visibility, + bfd_boolean constp, bfd_boolean volatilep) +{ + struct pr_handle *info = (struct pr_handle *) p; + char *method_type; + char *method_name; + + 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; + + method_name = strdup (info->stack->next->method); + /* 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 (! tg_fix_visibility (info, visibility)) + return FALSE; + + fprintf (info->f, "%s\t%s\t0;\"\tkind:p\ttype:%s\tclass:%s\taccess:%s\n", + method_name, info->filename, method_type, info->stack->type, + visibility_name (visibility)); + free (method_type); + free (method_name); + + return TRUE; +} + +/* Finish up a class. */ + +static bfd_boolean +tg_end_class_type (void *p) +{ + struct pr_handle *info = (struct pr_handle *) p; + + fprintf (info->f, "%s\t%s\t0;\"\tkind:c\ttype:%s", info->stack->type, + info->filename, info->stack->flavor); + if (info->stack->num_parents) + { + fprintf (info->f, "\tinherits:%s", info->stack->parents); + free (info->stack->parents); + } + fputc ('\n', info->f); + + return tg_end_struct_type (p); +} + +/* Push a type on the stack using a tag name. */ + +static bfd_boolean +tg_tag_type (void *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; + + return TRUE; +} + +/* Output a typedef. */ + +static bfd_boolean +tg_typdef (void *p, const char *name) +{ + struct pr_handle *info = (struct pr_handle *) p; + char *s; + + s = pop_type (info); + if (s == NULL) + return FALSE; + + fprintf (info->f, "%s\t%s\t0;\"\tkind:t\ttype:%s\n", name, + info->filename, 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 +tg_tag (void *p ATTRIBUTE_UNUSED, const char *name ATTRIBUTE_UNUSED) +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + + t = pop_type (info); + if (t == NULL) + return FALSE; + free (t); + + return TRUE; +} + +/* Output an integer constant. */ + +static bfd_boolean +tg_int_constant (void *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, "%s\t%s\t0;\"\tkind:v\ttype:const int\tvalue:%s\n", + name, info->filename, ab); + return TRUE; +} + +/* Output a floating point constant. */ + +static bfd_boolean +tg_float_constant (void *p, const char *name, double val) +{ + struct pr_handle *info = (struct pr_handle *) p; + + indent (info); + fprintf (info->f, "%s\t%s\t0;\"\tkind:v\ttype:const double\tvalue:%g\n", + name, info->filename, val); + return TRUE; +} + +/* Output a typed constant. */ + +static bfd_boolean +tg_typed_constant (void *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, "%s\t%s\t0;\"\tkind:v\ttype:const %s\tvalue:%s\n", + name, info->filename, t, ab); + + free (t); + + return TRUE; +} + +/* Output a variable. */ + +static bfd_boolean +tg_variable (void *p, const char *name, enum debug_var_kind kind, + bfd_vma val ATTRIBUTE_UNUSED) +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + const char *dname, *from_class; + + t = pop_type (info); + if (t == NULL) + return FALSE; + + dname = name; + if (info->demangler) + { + dname = info->demangler (info->abfd, name); + if (strcmp (name, dname) == 0) + { + free ((char *) dname); + dname = name; + } + } + + if (dname != name) + { + char *sep; + sep = strstr (dname, "::"); + if (sep) + { + *sep = 0; + name = sep + 2; + from_class = dname; + } + else + { + /* Obscure types as vts and type_info nodes. */ + name = dname; + from_class = NULL; + } + } + else + from_class = NULL; + + fprintf (info->f, "%s\t%s\t0;\"\tkind:v\ttype:%s", name, info->filename, t); + + switch (kind) + { + case DEBUG_STATIC: + case DEBUG_LOCAL_STATIC: + fprintf (info->f, "\tfile:"); + break; + case DEBUG_REGISTER: + fprintf (info->f, "\tregister:"); + break; + default: + break; + } + + if (from_class) + { + fprintf (info->f, "\tclass:%s",from_class); + free ((char *) dname); + } + + fprintf (info->f, "\n"); + + free (t); + + return TRUE; +} + +/* Start outputting a function. */ + +static bfd_boolean +tg_start_function (void *p, const char *name, bfd_boolean global) +{ + struct pr_handle *info = (struct pr_handle *) p; + const char *dname; + + if (! global) + info->stack->flavor = "static"; + else + info->stack->flavor = NULL; + + dname = name; + if (info->demangler) + { + dname = info->demangler (info->abfd, name); + if (strcmp (name, dname) == 0) + { + free ((char *) dname); + dname = name; + } + } + + if (! substitute_type (info, dname)) + return FALSE; + + if (dname != name) + { + char *sep; + sep = strstr (dname, "::"); + if (sep) + { + info->stack->method = dname; + *sep = 0; + name = sep + 2; + } + else + { + info->stack->method = ""; + name = dname; + } + sep = strchr (name, '('); + if (sep) + *sep = 0; + /* Obscure functions as type_info function. */ + } + else + info->stack->method = NULL; + + info->stack->parents = strdup (name); + + if (! info->stack->method && ! append_type (info, "(")) + return FALSE; + + info->parameter = 1; + + return TRUE; +} + +/* Output a function parameter. */ + +static bfd_boolean +tg_function_parameter (void *p, const char *name, enum debug_parm_kind kind, + bfd_vma val ATTRIBUTE_UNUSED) +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + + 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->stack->method) + { + if (info->parameter != 1 && ! append_type (info, ", ")) + return FALSE; + + if (kind == DEBUG_PARM_REG || kind == DEBUG_PARM_REF_REG) + if (! append_type (info, "register ")) + return FALSE; + + if (! append_type (info, t)) + return FALSE; + } + + free (t); + + ++info->parameter; + + return TRUE; +} + +/* Start writing out a block. */ + +static bfd_boolean +tg_start_block (void *p, bfd_vma addr) +{ + struct pr_handle *info = (struct pr_handle *) p; + char ab[20], kind, *partof; + char *t; + bfd_boolean local; + + if (info->parameter > 0) + { + info->parameter = 0; + + /* Delayed name. */ + fprintf (info->f, "%s\t%s\t", info->stack->parents, info->filename); + free (info->stack->parents); + + print_vma (addr, ab, TRUE, TRUE); + translate_addresses (info->abfd, ab, info->f, info->syms); + local = info->stack->flavor != NULL; + if (info->stack->method && *info->stack->method) + { + kind = 'm'; + partof = (char *) info->stack->method; + } + else + { + kind = 'f'; + partof = NULL; + if (! info->stack->method && ! append_type (info, ")")) + return FALSE; + } + t = pop_type (info); + if (t == NULL) + return FALSE; + fprintf (info->f, ";\"\tkind:%c\ttype:%s", kind, t); + if (local) + fputs ("\tfile:", info->f); + if (partof) + { + fprintf (info->f, "\tclass:%s", partof); + free (partof); + } + fputc ('\n', info->f); + } + + return TRUE; +} + +/* Write out line number information. */ + +static bfd_boolean +tg_lineno (void *p ATTRIBUTE_UNUSED, const char *filename ATTRIBUTE_UNUSED, + unsigned long lineno ATTRIBUTE_UNUSED, + bfd_vma addr ATTRIBUTE_UNUSED) +{ + return TRUE; +} + +/* Finish writing out a block. */ + +static bfd_boolean +tg_end_block (void *p ATTRIBUTE_UNUSED, bfd_vma addr ATTRIBUTE_UNUSED) +{ + return TRUE; +} + +/* Convert the visibility value into a human readable name. */ + +static const char * +visibility_name (enum debug_visibility visibility) +{ + const char *s; + + 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; + } + return s; +} diff --git a/contrib/binutils-2.17/binutils/rdcoff.c b/contrib/binutils-2.17/binutils/rdcoff.c new file mode 100644 index 0000000000..1eda3af195 --- /dev/null +++ b/contrib/binutils-2.17/binutils/rdcoff.c @@ -0,0 +1,874 @@ +/* stabs.c -- Parse COFF debugging information + Copyright 1996, 1999, 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 (struct coff_types *, int); +static debug_type parse_coff_type + (bfd *, struct coff_symbols *, struct coff_types *, long, int, + union internal_auxent *, bfd_boolean, void *); +static debug_type parse_coff_base_type + (bfd *, struct coff_symbols *, struct coff_types *, long, int, + union internal_auxent *, void *); +static debug_type parse_coff_struct_type + (bfd *, struct coff_symbols *, struct coff_types *, int, + union internal_auxent *, void *); +static debug_type parse_coff_enum_type + (bfd *, struct coff_symbols *, struct coff_types *, + union internal_auxent *, void *); +static bfd_boolean parse_coff_symbol + (bfd *, struct coff_types *, asymbol *, long, struct internal_syment *, + void *, debug_type, bfd_boolean); +static bfd_boolean external_coff_symbol_p (int sym_class); + +/* Return the slot for a type. */ + +static debug_type * +coff_get_slot (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 (bfd *abfd, struct coff_symbols *symbols, + struct coff_types *types, long coff_symno, int ntype, + union internal_auxent *pauxent, bfd_boolean useaux, + void *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 (bfd *abfd, struct coff_symbols *symbols, + struct coff_types *types, long coff_symno, int ntype, + union internal_auxent *pauxent, void *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 (bfd *abfd, struct coff_symbols *symbols, + struct coff_types *types, int ntype, + union internal_auxent *pauxent, void *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 (bfd *abfd, struct coff_symbols *symbols, + struct coff_types *types ATTRIBUTE_UNUSED, + union internal_auxent *pauxent, void *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 (bfd *abfd ATTRIBUTE_UNUSED, struct coff_types *types, + asymbol *sym, long coff_symno, + struct internal_syment *psyment, void *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 (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 (bfd *abfd, asymbol **syms, long symcount, void *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.17/binutils/rddbg.c b/contrib/binutils-2.17/binutils/rddbg.c new file mode 100644 index 0000000000..e977d8b5ef --- /dev/null +++ b/contrib/binutils-2.17/binutils/rddbg.c @@ -0,0 +1,447 @@ +/* rddbg.c -- Read debugging information into a generic form. + Copyright 1995, 1996, 1997, 2000, 2002, 2003, 2005 + 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 + (bfd *, asymbol **, long, void *, bfd_boolean *); +static bfd_boolean read_symbol_stabs_debugging_info + (bfd *, asymbol **, long, void *, bfd_boolean *); +static bfd_boolean read_ieee_debugging_info (bfd *, void *, bfd_boolean *); +static void save_stab (int, int, bfd_vma, const char *); +static void stab_context (void); +static void free_saved_stabs (void); + +/* Read debugging information from a BFD. Returns a generic debugging + pointer. */ + +void * +read_debugging_info (bfd *abfd, asymbol **syms, long symcount) +{ + void *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 (bfd *abfd, asymbol **syms, long symcount, + void *dhandle, bfd_boolean *pfound) +{ + static struct + { + const char *secname; + const char *strsecname; + } + names[] = + { + { ".stab", ".stabstr" }, + { "LC_SYMTAB.stabs", "LC_SYMTAB.stabstr" }, + { "$GDB_SYMBOLS$", "$GDB_STRINGS$" } + }; + unsigned int i; + void *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 (bfd *abfd, asymbol **syms, long symcount, + void *dhandle, bfd_boolean *pfound) +{ + void *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 (bfd *abfd, void *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 (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 (void) +{ + 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 (void) +{ + 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.17/binutils/readelf.c b/contrib/binutils-2.17/binutils/readelf.c new file mode 100644 index 0000000000..d8bd54f440 --- /dev/null +++ b/contrib/binutils-2.17/binutils/readelf.c @@ -0,0 +1,9362 @@ +/* readelf.c -- display contents of an ELF format file + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +/* The difference between readelf and objdump: + + Both programs are capable of displaying the contents of ELF format files, + so why does the binutils project have two file dumpers ? + + The reason is that objdump sees an ELF file through a BFD filter of the + world; if BFD has a bug where, say, it disagrees about a machine constant + in e_flags, then the odds are good that it will remain internally + consistent. The linker sees it the BFD way, objdump sees it the BFD way, + GAS sees it the BFD way. There was need for a tool to go find out what + the file actually says. + + This is why the readelf program does not link against the BFD library - it + exists as an independent program to help verify the correct working of BFD. + + There is also the case that readelf can provide more information about an + ELF file than is provided by objdump. In particular it can display DWARF + debugging information which (at the moment) objdump cannot. */ + +#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 "dwarf.h" + +#include "elf/common.h" +#include "elf/external.h" +#include "elf/internal.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/bfin.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/m32c.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/mt.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/crx.h" +#include "elf/iq2000.h" +#include "elf/xtensa.h" + +#include "aout/ar.h" + +#include "bucomm.h" +#include "getopt.h" +#include "libiberty.h" + +char *program_name = "readelf"; +static long archive_file_offset; +static unsigned long archive_file_size; +static unsigned long dynamic_addr; +static bfd_size_type dynamic_size; +static unsigned int dynamic_nent; +static char *dynamic_strings; +static unsigned long dynamic_strings_length; +static char *string_table; +static unsigned long string_table_length; +static unsigned long num_dynamic_syms; +static Elf_Internal_Sym *dynamic_symbols; +static Elf_Internal_Syminfo *dynamic_syminfo; +static unsigned long dynamic_syminfo_offset; +static unsigned int dynamic_syminfo_nent; +static char program_interpreter[64]; +static bfd_vma dynamic_info[DT_JMPREL + 1]; +static bfd_vma version_info[16]; +static Elf_Internal_Ehdr elf_header; +static Elf_Internal_Shdr *section_headers; +static Elf_Internal_Phdr *program_headers; +static Elf_Internal_Dyn *dynamic_section; +static Elf_Internal_Shdr *symtab_shndx_hdr; +static int show_name; +static int do_dynamic; +static int do_syms; +static int do_reloc; +static int do_sections; +static int do_section_groups; +static int do_section_details; +static int do_segments; +static int do_unwind; +static int do_using_dynamic; +static int do_header; +static int do_dump; +static int do_version; +static int do_wide; +static int do_histogram; +static int do_debugging; +static int do_arch; +static int do_notes; +static int is_32bit_elf; + +struct group_list +{ + struct group_list *next; + unsigned int section_index; +}; + +struct group +{ + struct group_list *root; + unsigned int group_index; +}; + +static size_t group_count; +static struct group *section_groups; +static struct group **section_headers_groups; + +/* A linked list of the section names for which dumps were requested + by name. */ +struct dump_list_entry +{ + char *name; + int type; + struct dump_list_entry *next; +}; +static struct dump_list_entry *dump_sects_byname; + +/* A dynamic array of flags indicating for which sections a hex dump + has been requested (via the -x switch) and/or a disassembly dump + (via the -i switch). */ +char *cmdline_dump_sects = NULL; +unsigned num_cmdline_dump_sects = 0; + +/* A dynamic array of flags indicating for which sections a dump of + some kind has been requested. It is reset on a per-object file + basis and then initialised from the cmdline_dump_sects array, + the results of interpreting the -w switch, and the + dump_sects_byname list. */ +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 print a vma value. */ +typedef enum print_mode +{ + HEX, + DEC, + DEC_5, + UNSIGNED, + PREFIX_HEX, + FULL_HEX, + LONG_HEX +} +print_mode; + +static void (*byte_put) (unsigned char *, bfd_vma, int); + +#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)) + +#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)) + +#define VALID_DYNAMIC_NAME(offset) ((dynamic_strings != NULL) && (offset < dynamic_strings_length)) +/* GET_DYNAMIC_NAME asssumes that VALID_DYNAMIC_NAME has + already been called and verified that the string exists. */ +#define GET_DYNAMIC_NAME(offset) (dynamic_strings + offset) + +/* This is just a bit of syntatic sugar. */ +#define streq(a,b) (strcmp ((a), (b)) == 0) +#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) + +static void * +get_data (void *var, FILE *file, long offset, size_t size, size_t nmemb, + const char *reason) +{ + void *mvar; + + if (size == 0 || nmemb == 0) + return NULL; + + if (fseek (file, archive_file_offset + offset, SEEK_SET)) + { + error (_("Unable to seek to 0x%lx for %s\n"), + archive_file_offset + offset, reason); + return NULL; + } + + mvar = var; + if (mvar == NULL) + { + /* Check for overflow. */ + if (nmemb < (~(size_t) 0 - 1) / size) + /* + 1 so that we can '\0' terminate invalid string table sections. */ + mvar = malloc (size * nmemb + 1); + + if (mvar == NULL) + { + error (_("Out of memory allocating 0x%lx bytes for %s\n"), + (unsigned long)(size * nmemb), reason); + return NULL; + } + + ((char *) mvar)[size * nmemb] = '\0'; + } + + if (fread (mvar, size, nmemb, file) != nmemb) + { + error (_("Unable to read in 0x%lx bytes of %s\n"), + (unsigned long)(size * nmemb), reason); + if (mvar != var) + free (mvar); + return NULL; + } + + return mvar; +} + +static void +byte_put_little_endian (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 (); + } +} + +#if defined BFD64 && !BFD_HOST_64BIT_LONG +static int +print_dec_vma (bfd_vma vma, int is_signed) +{ + char buf[40]; + char *bufp = buf; + int nc = 0; + + if (is_signed && (bfd_signed_vma) vma < 0) + { + vma = -vma; + putchar ('-'); + nc = 1; + } + + do + { + *bufp++ = '0' + vma % 10; + vma /= 10; + } + while (vma != 0); + nc += bufp - buf; + + while (bufp > buf) + putchar (*--bufp); + return nc; +} + +static int +print_hex_vma (bfd_vma vma) +{ + char buf[32]; + char *bufp = buf; + int nc; + + do + { + char digit = '0' + (vma & 0x0f); + if (digit > '9') + digit += 'a' - '0' - 10; + *bufp++ = digit; + vma >>= 4; + } + while (vma != 0); + nc = bufp - buf; + + while (bufp > buf) + putchar (*--bufp); + return nc; +} +#endif + +/* Print a VMA value. */ +static int +print_vma (bfd_vma vma, print_mode mode) +{ +#ifdef BFD64 + if (is_32bit_elf) +#endif + { + switch (mode) + { + case FULL_HEX: + return printf ("0x%8.8lx", (unsigned long) vma); + + case LONG_HEX: + return printf ("%8.8lx", (unsigned long) vma); + + case DEC_5: + if (vma <= 99999) + return printf ("%5ld", (long) vma); + /* Drop through. */ + + case PREFIX_HEX: + return printf ("0x%lx", (unsigned long) vma); + + case HEX: + return printf ("%lx", (unsigned long) vma); + + case DEC: + return printf ("%ld", (unsigned long) vma); + + case UNSIGNED: + return printf ("%lu", (unsigned long) vma); + } + } +#ifdef BFD64 + else + { + int nc = 0; + + switch (mode) + { + case FULL_HEX: + nc = printf ("0x"); + /* Drop through. */ + + case LONG_HEX: + printf_vma (vma); + return nc + 16; + + case PREFIX_HEX: + nc = printf ("0x"); + /* Drop through. */ + + case HEX: +#if BFD_HOST_64BIT_LONG + return nc + printf ("%lx", vma); +#else + return nc + print_hex_vma (vma); +#endif + + case DEC: +#if BFD_HOST_64BIT_LONG + return printf ("%ld", vma); +#else + return print_dec_vma (vma, 1); +#endif + + case DEC_5: +#if BFD_HOST_64BIT_LONG + if (vma <= 99999) + return printf ("%5ld", vma); + else + return printf ("%#lx", vma); +#else + if (vma <= 99999) + return printf ("%5ld", _bfd_int64_low (vma)); + else + return print_hex_vma (vma); +#endif + + case UNSIGNED: +#if BFD_HOST_64BIT_LONG + return printf ("%lu", vma); +#else + return print_dec_vma (vma, 0); +#endif + } + } +#endif + return 0; +} + +/* 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 (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 void +byte_put_big_endian (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 (); + } +} + +/* Return a pointer to section NAME, or NULL if no such section exists. */ + +static Elf_Internal_Shdr * +find_section (const char *name) +{ + unsigned int i; + + for (i = 0; i < elf_header.e_shnum; i++) + if (streq (SECTION_NAME (section_headers + i), name)) + return section_headers + i; + + return NULL; +} + +/* Guess the relocation size commonly used by the specific machines. */ + +static int +guess_is_rela (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_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_CRX: + case EM_VAX: + case EM_IP2K: + case EM_IP2K_OLD: + case EM_IQ2000: + case EM_XTENSA: + case EM_XTENSA_OLD: + case EM_M32R: + case EM_M32C: + case EM_MT: + case EM_BLACKFIN: + case EM_NIOS32: + case EM_ALTERA_NIOS2: + 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 *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 = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs")); + if (!erelas) + return 0; + + nrelas = rel_size / sizeof (Elf32_External_Rela); + + relas = cmalloc (nrelas, sizeof (Elf_Internal_Rela)); + + if (relas == NULL) + { + free (erelas); + 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 = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs")); + if (!erelas) + return 0; + + nrelas = rel_size / sizeof (Elf64_External_Rela); + + relas = cmalloc (nrelas, sizeof (Elf_Internal_Rela)); + + if (relas == NULL) + { + free (erelas); + 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); + } + *relasp = relas; + *nrelasp = nrelas; + return 1; +} + +static int +slurp_rel_relocs (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 = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs")); + if (!erels) + return 0; + + nrels = rel_size / sizeof (Elf32_External_Rel); + + rels = cmalloc (nrels, sizeof (Elf_Internal_Rela)); + + if (rels == NULL) + { + free (erels); + 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 = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs")); + if (!erels) + return 0; + + nrels = rel_size / sizeof (Elf64_External_Rel); + + rels = cmalloc (nrels, sizeof (Elf_Internal_Rela)); + + if (rels == NULL) + { + free (erels); + 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); + } + *relsp = rels; + *nrelsp = nrels; + return 1; +} + +/* Display the contents of the relocation data found at the specified + offset. */ + +static int +dump_relocations (FILE *file, + unsigned long rel_offset, + unsigned long rel_size, + Elf_Internal_Sym *symtab, + unsigned long nsyms, + char *strtab, + unsigned long strtablen, + 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 = 0; + bfd_vma type3 = 0; + + 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_CRX: + rtype = elf_crx_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; + + case EM_M32C: + rtype = elf_m32c_reloc_type (type); + break; + + case EM_MT: + rtype = elf_mt_reloc_type (type); + break; + + case EM_BLACKFIN: + rtype = elf_bfin_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 (elf_header.e_machine == EM_ALPHA + && streq (rtype, "R_ALPHA_LITUSE") + && is_rela) + { + switch (rels[i].r_addend) + { + case LITUSE_ALPHA_ADDR: rtype = "ADDR"; break; + case LITUSE_ALPHA_BASE: rtype = "BASE"; break; + case LITUSE_ALPHA_BYTOFF: rtype = "BYTOFF"; break; + case LITUSE_ALPHA_JSR: rtype = "JSR"; break; + case LITUSE_ALPHA_TLSGD: rtype = "TLSGD"; break; + case LITUSE_ALPHA_TLSLDM: rtype = "TLSLDM"; break; + case LITUSE_ALPHA_JSRDIRECT: rtype = "JSRDIRECT"; break; + default: rtype = NULL; + } + if (rtype) + printf (" (%s)", rtype); + else + { + putchar (' '); + printf (_(""), + (unsigned long) rels[i].r_addend); + } + } + else 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_HIRESERVE) + 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 if (elf_header.e_machine == EM_X86_64 + && psym->st_shndx == SHN_X86_64_LCOMMON) + sec_name = "LARGE_COMMON"; + else if (elf_header.e_machine == EM_IA_64 + && elf_header.e_ident[EI_OSABI] == ELFOSABI_HPUX + && psym->st_shndx == SHN_IA_64_ANSI_COMMON) + sec_name = "ANSI_COM"; + 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 if (psym->st_name >= strtablen) + 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 && streq (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 (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 (unsigned long type) +{ + switch (type) + { + case DT_SPARC_REGISTER: return "SPARC_REGISTER"; + default: + return NULL; + } +} + +static const char * +get_ppc_dynamic_type (unsigned long type) +{ + switch (type) + { + case DT_PPC_GOT: return "PPC_GOT"; + default: + return NULL; + } +} + +static const char * +get_ppc64_dynamic_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 (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"; + case DT_HP_EPLTREL: return "HP_GST_EPLTREL"; + case DT_HP_EPLTRELSZ: return "HP_GST_EPLTRELSZ"; + case DT_HP_FILTERED: return "HP_FILTERED"; + case DT_HP_FILTER_TLS: return "HP_FILTER_TLS"; + case DT_HP_COMPAT_FILTERED: return "HP_COMPAT_FILTERED"; + case DT_HP_LAZYLOAD: return "HP_LAZYLOAD"; + case DT_HP_BIND_NOW_COUNT: return "HP_BIND_NOW_COUNT"; + case DT_PLT: return "PLT"; + case DT_PLT_SIZE: return "PLT_SIZE"; + case DT_DLT: return "DLT"; + case DT_DLT_SIZE: return "DLT_SIZE"; + default: + return NULL; + } +} + +static const char * +get_ia64_dynamic_type (unsigned long type) +{ + switch (type) + { + case DT_IA_64_PLT_RESERVE: return "IA_64_PLT_RESERVE"; + default: + return NULL; + } +} + +static const char * +get_alpha_dynamic_type (unsigned long type) +{ + switch (type) + { + case DT_ALPHA_PLTRO: return "ALPHA_PLTRO"; + default: + return NULL; + } +} + +static const char * +get_dynamic_type (unsigned long type) +{ + static char buff[64]; + + 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_TLSDESC_GOT: return "TLSDESC_GOT"; + case DT_TLSDESC_PLT: return "TLSDESC_PLT"; + 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_PPC: + result = get_ppc_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; + case EM_ALPHA: + result = get_alpha_dynamic_type (type); + break; + default: + result = NULL; + break; + } + + if (result != NULL) + return result; + + snprintf (buff, sizeof (buff), _("Processor Specific: %lx"), type); + } + else if (((type >= DT_LOOS) && (type <= DT_HIOS)) + || (elf_header.e_machine == EM_PARISC + && (type >= OLD_DT_LOOS) && (type <= OLD_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; + + snprintf (buff, sizeof (buff), _("Operating System specific: %lx"), + type); + } + else + snprintf (buff, sizeof (buff), _(": %lx"), type); + + return buff; + } +} + +static char * +get_file_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)) + snprintf (buff, sizeof (buff), _("Processor Specific: (%x)"), e_type); + else if ((e_type >= ET_LOOS) && (e_type <= ET_HIOS)) + snprintf (buff, sizeof (buff), _("OS Specific: (%x)"), e_type); + else + snprintf (buff, sizeof (buff), _(": %x"), e_type); + return buff; + } +} + +static char * +get_machine_name (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_CRX: return "National Semiconductor CRX microprocessor"; + 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"; + case EM_M32C: return "Renesas M32c"; + case EM_MT: return "Morpho Techologies MT processor"; + case EM_BLACKFIN: return "Analog Devices Blackfin"; + case EM_NIOS32: return "Altera Nios"; + case EM_ALTERA_NIOS2: return "Altera Nios II"; + case EM_XC16X: return "Infineon Technologies xc16x"; + default: + snprintf (buff, sizeof (buff), _(": %x"), e_machine); + return buff; + } +} + +static void +decode_ARM_machine_flags (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_VER3: + strcat (buf, ", Version3 EABI"); + break; + + case EF_ARM_EABI_VER4: + strcat (buf, ", Version4 EABI"); + goto eabi; + + case EF_ARM_EABI_VER5: + strcat (buf, ", Version5 EABI"); + 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_BE8: + strcat (buf, ", BE8"); + break; + + case EF_ARM_LE8: + strcat (buf, ", LE8"); + 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_VFP_FLOAT: + strcat (buf, ", VFP"); + break; + + case EF_ARM_MAVERICK_FLOAT: + strcat (buf, ", Maverick FP"); + break; + + default: + unknown = 1; + break; + } + } + } + + if (unknown) + strcat (buf,", "); +} + +static char * +get_machine_flags (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_CYGNUS_FRV: + switch (e_flags & EF_FRV_CPU_MASK) + { + case EF_FRV_CPU_GENERIC: + break; + + default: + strcat (buf, ", fr???"); + break; + + case EF_FRV_CPU_FR300: + strcat (buf, ", fr300"); + break; + + case EF_FRV_CPU_FR400: + strcat (buf, ", fr400"); + break; + case EF_FRV_CPU_FR405: + strcat (buf, ", fr405"); + break; + + case EF_FRV_CPU_FR450: + strcat (buf, ", fr450"); + break; + + case EF_FRV_CPU_FR500: + strcat (buf, ", fr500"); + break; + case EF_FRV_CPU_FR550: + strcat (buf, ", fr550"); + break; + + case EF_FRV_CPU_SIMPLE: + strcat (buf, ", simple"); + break; + case EF_FRV_CPU_TOMCAT: + strcat (buf, ", tomcat"); + break; + } + break; + + case EM_68K: + if (e_flags & EF_M68K_CPU32) + strcat (buf, ", cpu32"); + if (e_flags & EF_M68K_M68000) + strcat (buf, ", m68000"); + if (e_flags & EF_M68K_ISA_MASK) + { + char const *isa = _("unknown"); + char const *mac = _("unknown mac"); + char const *additional = NULL; + + switch (e_flags & EF_M68K_ISA_MASK) + { + case EF_M68K_ISA_A_NODIV: + isa = "A"; + additional = ", nodiv"; + break; + case EF_M68K_ISA_A: + isa = "A"; + break; + case EF_M68K_ISA_A_PLUS: + isa = "A+"; + break; + case EF_M68K_ISA_B_NOUSP: + isa = "B"; + additional = ", nousp"; + break; + case EF_M68K_ISA_B: + isa = "B"; + break; + } + strcat (buf, ", cf, isa "); + strcat (buf, isa); + if (additional) + strcat (buf, additional); + if (e_flags & EF_M68K_FLOAT) + strcat (buf, ", float"); + switch (e_flags & EF_M68K_MAC_MASK) + { + case 0: + mac = NULL; + break; + case EF_M68K_MAC: + mac = "mac"; + break; + case EF_M68K_EMAC: + mac = "emac"; + break; + } + if (mac) + { + strcat (buf, ", "); + strcat (buf, mac); + } + } + 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_V850E1_ARCH: + strcat (buf, ", v850e1"); + break; + 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 E_MIPS_MACH_9000: strcat (buf, ", 9000"); 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; + case E_MIPS_ARCH_64R2: strcat (buf, ", mips64r2"); break; + default: strcat (buf, ", unknown ISA"); break; + } + + break; + + case EM_SH: + switch ((e_flags & EF_SH_MACH_MASK)) + { + case EF_SH1: strcat (buf, ", sh1"); break; + case EF_SH2: strcat (buf, ", sh2"); break; + case EF_SH3: strcat (buf, ", sh3"); break; + case EF_SH_DSP: strcat (buf, ", sh-dsp"); break; + case EF_SH3_DSP: strcat (buf, ", sh3-dsp"); break; + case EF_SH4AL_DSP: strcat (buf, ", sh4al-dsp"); break; + case EF_SH3E: strcat (buf, ", sh3e"); break; + case EF_SH4: strcat (buf, ", sh4"); break; + case EF_SH5: strcat (buf, ", sh5"); break; + case EF_SH2E: strcat (buf, ", sh2e"); break; + case EF_SH4A: strcat (buf, ", sh4a"); break; + case EF_SH2A: strcat (buf, ", sh2a"); break; + case EF_SH4_NOFPU: strcat (buf, ", sh4-nofpu"); break; + case EF_SH4A_NOFPU: strcat (buf, ", sh4a-nofpu"); break; + case EF_SH2A_NOFPU: strcat (buf, ", sh2a-nofpu"); break; + case EF_SH3_NOMMU: strcat (buf, ", sh3-nommu"); break; + case EF_SH4_NOMMU_NOFPU: strcat (buf, ", sh4-nommu-nofpu"); break; + case EF_SH2A_SH4_NOFPU: strcat (buf, ", sh2a-nofpu-or-sh4-nommu-nofpu"); break; + case EF_SH2A_SH3_NOFPU: strcat (buf, ", sh2a-nofpu-or-sh3-nommu"); break; + case EF_SH2A_SH4: strcat (buf, ", sh2a-or-sh4"); break; + case EF_SH2A_SH3E: strcat (buf, ", sh2a-or-sh3e"); 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_osabi_name (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: + snprintf (buff, sizeof (buff), _(""), osabi); + return buff; + } +} + +static const char * +get_arm_segment_type (unsigned long type) +{ + switch (type) + { + case PT_ARM_EXIDX: + return "EXIDX"; + default: + break; + } + + return NULL; +} + +static const char * +get_mips_segment_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 (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_HP_OPT_ANNOT: return "HP_OPT_ANNOT"; + case PT_HP_HSL_ANNOT: return "HP_HSL_ANNOT"; + case PT_HP_STACK: return "HP_STACK"; + case PT_HP_CORE_UTSNAME: return "HP_CORE_UTSNAME"; + case PT_PARISC_ARCHEXT: return "PARISC_ARCHEXT"; + case PT_PARISC_UNWIND: return "PARISC_UNWIND"; + case PT_PARISC_WEAKORDER: return "PARISC_WEAKORDER"; + default: + break; + } + + return NULL; +} + +static const char * +get_ia64_segment_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 (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"; + case PT_GNU_STACK: return "GNU_STACK"; + case PT_GNU_RELRO: return "GNU_RELRO"; + + default: + if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC)) + { + const char *result; + + switch (elf_header.e_machine) + { + case EM_ARM: + result = get_arm_segment_type (p_type); + break; + 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 + snprintf (buff, sizeof (buff), _(": %lx"), p_type); + + return buff; + } +} + +static const char * +get_mips_section_type_name (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 (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"; + case SHT_PARISC_ANNOT: return "PARISC_ANNOT"; + case SHT_PARISC_SYMEXTN: return "PARISC_SYMEXTN"; + case SHT_PARISC_STUBS: return "PARISC_STUBS"; + case SHT_PARISC_DLKM: return "PARISC_DLKM"; + default: + break; + } + return NULL; +} + +static const char * +get_ia64_section_type_name (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_x86_64_section_type_name (unsigned int sh_type) +{ + switch (sh_type) + { + case SHT_X86_64_UNWIND: return "X86_64_UNWIND"; + default: + break; + } + return NULL; +} + +static const char * +get_arm_section_type_name (unsigned int sh_type) +{ + switch (sh_type) + { + case SHT_ARM_EXIDX: + return "ARM_EXIDX"; + case SHT_ARM_PREEMPTMAP: + return "ARM_PREEMPTMAP"; + case SHT_ARM_ATTRIBUTES: + return "ARM_ATTRIBUTES"; + default: + break; + } + return NULL; +} + +static const char * +get_section_type_name (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; + case EM_X86_64: + result = get_x86_64_section_type_name (sh_type); + break; + case EM_ARM: + result = get_arm_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 + snprintf (buff, sizeof (buff), _(": %x"), sh_type); + + return buff; + } +} + +#define OPTION_DEBUG_DUMP 512 + +static 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'}, + {"section-groups", no_argument, 0, 'g'}, + {"section-details", no_argument, 0, 't'}, + {"full-section-name",no_argument, 0, 'N'}, + {"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 (void) +{ + 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\ + -g --section-groups Display the section groups\n\ + -t --section-details Display the section details\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 section (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[liaprmfFsoR] or\n\ + --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=str,=loc,=Ranges]\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\ + @ Read options from \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); +} + +/* Record the fact that the user wants the contents of section number + SECTION to be displayed using the method(s) encoded as flags bits + in TYPE. Note, TYPE can be zero if we are creating the array for + the first time. */ + +static void +request_dump (unsigned int section, int type) +{ + if (section >= num_dump_sects) + { + char *new_dump_sects; + + new_dump_sects = 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; +} + +/* Request a dump by section name. */ + +static void +request_dump_byname (const char *section, int type) +{ + struct dump_list_entry *new_request; + + new_request = malloc (sizeof (struct dump_list_entry)); + if (!new_request) + error (_("Out of memory allocating dump request table.")); + + new_request->name = strdup (section); + if (!new_request->name) + error (_("Out of memory allocating dump request table.")); + + new_request->type = type; + + new_request->next = dump_sects_byname; + dump_sects_byname = new_request; +} + +static void +parse_args (int argc, char **argv) +{ + int c; + + if (argc < 2) + usage (); + + while ((c = getopt_long + (argc, argv, "ersuahnldSDAINtgw::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_section_groups++; + do_segments++; + do_version++; + do_histogram++; + do_arch++; + do_notes++; + break; + case 'g': + do_section_groups++; + break; + case 't': + case 'N': + do_sections++; + do_section_details++; + 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); + else + request_dump_byname (optarg, HEX_DUMP); + break; + 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': + do_debug_aranges = 1; + break; + + case 'R': + do_debug_ranges = 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 + { + typedef struct + { + const char * option; + int * variable; + } + debug_dump_long_opts; + + debug_dump_long_opts opts_table [] = + { + /* Please keep this table alpha- sorted. */ + { "Ranges", & do_debug_ranges }, + { "abbrev", & do_debug_abbrevs }, + { "aranges", & do_debug_aranges }, + { "frames", & do_debug_frames }, + { "frames-interp", & do_debug_frames_interp }, + { "info", & do_debug_info }, + { "line", & do_debug_lines }, + { "loc", & do_debug_loc }, + { "macro", & do_debug_macinfo }, + { "pubnames", & do_debug_pubnames }, + /* This entry is for compatability + with earlier versions of readelf. */ + { "ranges", & do_debug_aranges }, + { "str", & do_debug_str }, + { NULL, NULL } + }; + + const char *p; + + do_debugging = 0; + + p = optarg; + while (*p) + { + debug_dump_long_opts * entry; + + for (entry = opts_table; entry->option; entry++) + { + size_t len = strlen (entry->option); + + if (strneq (p, entry->option, len) + && (p[len] == ',' || p[len] == '\0')) + { + * entry->variable = 1; + + /* The --debug-dump=frames-interp option also + enables the --debug-dump=frames option. */ + if (do_debug_frames_interp) + do_debug_frames = 1; + + p += len; + break; + } + } + + if (entry->option == 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: +#ifdef SUPPORT_DISASSEMBLY + oops: +#endif + /* 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 + && !do_section_groups) + usage (); + else if (argc < 3) + { + warn (_("Nothing to do.\n")); + usage (); + } +} + +static const char * +get_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: + snprintf (buff, sizeof (buff), _(""), elf_class); + return buff; + } +} + +static const char * +get_data_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: + snprintf (buff, sizeof (buff), _(""), encoding); + return buff; + } +} + +/* Decode the data held in 'elf_header'. */ + +static int +process_file_header (void) +{ + 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 *file, Elf_Internal_Phdr *program_headers) +{ + Elf32_External_Phdr *phdrs; + Elf32_External_Phdr *external; + Elf_Internal_Phdr *internal; + unsigned int i; + + phdrs = 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 *file, Elf_Internal_Phdr *program_headers) +{ + Elf64_External_Phdr *phdrs; + Elf64_External_Phdr *external; + Elf_Internal_Phdr *internal; + unsigned int i; + + phdrs = 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_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_align = BYTE_GET (external->p_align); + } + + free (phdrs); + + return 1; +} + +/* Returns 1 if the program headers were read into `program_headers'. */ + +static int +get_program_headers (FILE *file) +{ + Elf_Internal_Phdr *phdrs; + + /* Check cache of prior read. */ + if (program_headers != NULL) + return 1; + + phdrs = cmalloc (elf_header.e_phnum, sizeof (Elf_Internal_Phdr)); + + if (phdrs == NULL) + { + error (_("Out of memory\n")); + return 0; + } + + if (is_32bit_elf + ? get_32bit_program_headers (file, phdrs) + : get_64bit_program_headers (file, phdrs)) + { + program_headers = phdrs; + return 1; + } + + free (phdrs); + return 0; +} + +/* Returns 1 if the program headers were loaded. */ + +static int +process_program_headers (FILE *file) +{ + 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"); + } + + if (! get_program_headers (file)) + 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")); + } + } + + 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_DYNAMIC: + if (dynamic_addr) + error (_("more than one dynamic segment\n")); + + /* Try to locate the .dynamic section. If there is + a section header table, we can easily locate it. */ + if (section_headers != NULL) + { + Elf_Internal_Shdr *sec; + + sec = find_section (".dynamic"); + if (sec == NULL || sec->sh_size == 0) + { + error (_("no .dynamic section in the dynamic segment")); + break; + } + + dynamic_addr = sec->sh_offset; + dynamic_size = sec->sh_size; + + if (dynamic_addr < segment->p_offset + || dynamic_addr > segment->p_offset + segment->p_filesz) + warn (_("the .dynamic section is not contained within the dynamic segment")); + else if (dynamic_addr > segment->p_offset) + warn (_("the .dynamic section is not the first section in the dynamic segment.")); + } + else + { + /* Otherwise, we can only assume that the .dynamic + section is the first section in the DYNAMIC segment. */ + dynamic_addr = segment->p_offset; + dynamic_size = segment->p_filesz; + } + break; + + case PT_INTERP: + if (fseek (file, archive_file_offset + (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 (do_segments && section_headers != NULL && string_table != NULL) + { + printf (_("\n Section to Segment mapping:\n")); + printf (_(" Segment Sections...\n")); + + 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 (ELF_IS_SECTION_IN_SEGMENT_MEMORY(section, segment)) + printf ("%s ", SECTION_NAME (section)); + } + + putc ('\n',stdout); + } + } + + return 1; +} + + +/* Find the file offset corresponding to VMA by using the program headers. */ + +static long +offset_from_vma (FILE *file, bfd_vma vma, bfd_size_type size) +{ + Elf_Internal_Phdr *seg; + + if (! get_program_headers (file)) + { + warn (_("Cannot interpret virtual addresses without program headers.\n")); + return (long) vma; + } + + for (seg = program_headers; + seg < program_headers + elf_header.e_phnum; + ++seg) + { + if (seg->p_type != PT_LOAD) + continue; + + if (vma >= (seg->p_vaddr & -seg->p_align) + && vma + size <= seg->p_vaddr + seg->p_filesz) + return vma - seg->p_vaddr + seg->p_offset; + } + + warn (_("Virtual address 0x%lx not located in any PT_LOAD segment.\n"), + (long) vma); + return (long) vma; +} + + +static int +get_32bit_section_headers (FILE *file, unsigned int num) +{ + Elf32_External_Shdr *shdrs; + Elf_Internal_Shdr *internal; + unsigned int i; + + shdrs = get_data (NULL, file, elf_header.e_shoff, + elf_header.e_shentsize, num, _("section headers")); + if (!shdrs) + return 0; + + section_headers = cmalloc (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 *file, unsigned int num) +{ + Elf64_External_Shdr *shdrs; + Elf_Internal_Shdr *internal; + unsigned int i; + + shdrs = get_data (NULL, file, elf_header.e_shoff, + elf_header.e_shentsize, num, _("section headers")); + if (!shdrs) + return 0; + + section_headers = cmalloc (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_size = BYTE_GET (shdrs[i].sh_size); + internal->sh_entsize = BYTE_GET (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 *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 = get_data (NULL, file, section->sh_offset, 1, 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 = get_data (NULL, file, symtab_shndx_hdr->sh_offset, + 1, symtab_shndx_hdr->sh_size, _("symtab shndx")); + if (!shndx) + { + free (esyms); + return NULL; + } + } + + number = section->sh_size / section->sh_entsize; + isyms = cmalloc (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 *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 = get_data (NULL, file, section->sh_offset, 1, 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 = get_data (NULL, file, symtab_shndx_hdr->sh_offset, + 1, symtab_shndx_hdr->sh_size, _("symtab shndx")); + if (!shndx) + { + free (esyms); + return NULL; + } + } + + number = section->sh_size / section->sh_entsize; + isyms = cmalloc (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_GET (esyms[j].st_value); + psym->st_size = BYTE_GET (esyms[j].st_size); + } + + if (shndx) + free (shndx); + free (esyms); + + return isyms; +} + +static const char * +get_elf_section_flags (bfd_vma sh_flags) +{ + static char buff[1024]; + char *p = buff; + int field_size = is_32bit_elf ? 8 : 16; + int index, size = sizeof (buff) - (field_size + 4 + 1); + bfd_vma os_flags = 0; + bfd_vma proc_flags = 0; + bfd_vma unknown_flags = 0; + const struct + { + const char *str; + int len; + } + flags [] = + { + { "WRITE", 5 }, + { "ALLOC", 5 }, + { "EXEC", 4 }, + { "MERGE", 5 }, + { "STRINGS", 7 }, + { "INFO LINK", 9 }, + { "LINK ORDER", 10 }, + { "OS NONCONF", 10 }, + { "GROUP", 5 }, + { "TLS", 3 } + }; + + if (do_section_details) + { + sprintf (buff, "[%*.*lx]: ", + field_size, field_size, (unsigned long) sh_flags); + p += field_size + 4; + } + + while (sh_flags) + { + bfd_vma flag; + + flag = sh_flags & - sh_flags; + sh_flags &= ~ flag; + + if (do_section_details) + { + switch (flag) + { + case SHF_WRITE: index = 0; break; + case SHF_ALLOC: index = 1; break; + case SHF_EXECINSTR: index = 2; break; + case SHF_MERGE: index = 3; break; + case SHF_STRINGS: index = 4; break; + case SHF_INFO_LINK: index = 5; break; + case SHF_LINK_ORDER: index = 6; break; + case SHF_OS_NONCONFORMING: index = 7; break; + case SHF_GROUP: index = 8; break; + case SHF_TLS: index = 9; break; + + default: + index = -1; + break; + } + + if (index != -1) + { + if (p != buff + field_size + 4) + { + if (size < (10 + 2)) + abort (); + size -= 2; + *p++ = ','; + *p++ = ' '; + } + + size -= flags [index].len; + p = stpcpy (p, flags [index].str); + } + else if (flag & SHF_MASKOS) + os_flags |= flag; + else if (flag & SHF_MASKPROC) + proc_flags |= flag; + else + unknown_flags |= flag; + } + else + { + switch (flag) + { + case SHF_WRITE: *p = 'W'; break; + case SHF_ALLOC: *p = 'A'; break; + case SHF_EXECINSTR: *p = 'X'; break; + case SHF_MERGE: *p = 'M'; break; + case SHF_STRINGS: *p = 'S'; break; + case SHF_INFO_LINK: *p = 'I'; break; + case SHF_LINK_ORDER: *p = 'L'; break; + case SHF_OS_NONCONFORMING: *p = 'O'; break; + case SHF_GROUP: *p = 'G'; break; + case SHF_TLS: *p = 'T'; break; + + default: + if (elf_header.e_machine == EM_X86_64 + && flag == SHF_X86_64_LARGE) + *p = 'l'; + else if (flag & SHF_MASKOS) + { + *p = 'o'; + sh_flags &= ~ SHF_MASKOS; + } + else if (flag & SHF_MASKPROC) + { + *p = 'p'; + sh_flags &= ~ SHF_MASKPROC; + } + else + *p = 'x'; + break; + } + p++; + } + } + + if (do_section_details) + { + if (os_flags) + { + size -= 5 + field_size; + if (p != buff + field_size + 4) + { + if (size < (2 + 1)) + abort (); + size -= 2; + *p++ = ','; + *p++ = ' '; + } + sprintf (p, "OS (%*.*lx)", field_size, field_size, + (unsigned long) os_flags); + p += 5 + field_size; + } + if (proc_flags) + { + size -= 7 + field_size; + if (p != buff + field_size + 4) + { + if (size < (2 + 1)) + abort (); + size -= 2; + *p++ = ','; + *p++ = ' '; + } + sprintf (p, "PROC (%*.*lx)", field_size, field_size, + (unsigned long) proc_flags); + p += 7 + field_size; + } + if (unknown_flags) + { + size -= 10 + field_size; + if (p != buff + field_size + 4) + { + if (size < (2 + 1)) + abort (); + size -= 2; + *p++ = ','; + *p++ = ' '; + } + sprintf (p, "UNKNOWN (%*.*lx)", field_size, field_size, + (unsigned long) unknown_flags); + p += 10 + field_size; + } + } + + *p = '\0'; + return buff; +} + +static int +process_section_headers (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. */ + if (SECTION_HEADER_INDEX (elf_header.e_shstrndx) < elf_header.e_shnum) + { + section = SECTION_HEADER (elf_header.e_shstrndx); + + if (section->sh_size != 0) + { + string_table = get_data (NULL, file, section->sh_offset, + 1, section->sh_size, _("string table")); + + string_table_length = string_table != NULL ? section->sh_size : 0; + } + } + + /* 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; + + eh_addr_size = is_32bit_elf ? 4 : 8; + switch (elf_header.e_machine) + { + case EM_MIPS: + case EM_MIPS_RS3_LE: + /* The 64-bit MIPS EABI uses a combination of 32-bit ELF and 64-bit + FDE addresses. However, the ABI also has a semi-official ILP32 + variant for which the normal FDE address size rules apply. + + GCC 4.0 marks EABI64 objects with a dummy .gcc_compiled_longXX + section, where XX is the size of longs in bits. Unfortunately, + earlier compilers provided no way of distinguishing ILP32 objects + from LP64 objects, so if there's any doubt, we should assume that + the official LP64 form is being used. */ + if ((elf_header.e_flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI64 + && find_section (".gcc_compiled_long32") == NULL) + eh_addr_size = 8; + break; + } + +#define CHECK_ENTSIZE_VALUES(section, i, size32, size64) \ + do \ + { \ + size_t expected_entsize \ + = is_32bit_elf ? size32 : size64; \ + if (section->sh_entsize != expected_entsize) \ + error (_("Section %d has invalid sh_entsize %lx (expected %lx)\n"), \ + i, (unsigned long int) section->sh_entsize, \ + (unsigned long int) expected_entsize); \ + section->sh_entsize = expected_entsize; \ + } \ + while (0) +#define CHECK_ENTSIZE(section, i, type) \ + CHECK_ENTSIZE_VALUES (section, i, sizeof (Elf32_External_##type), \ + sizeof (Elf64_External_##type)) + + 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; + } + + CHECK_ENTSIZE (section, i, Sym); + num_dynamic_syms = section->sh_size / section->sh_entsize; + dynamic_symbols = GET_ELF_SYMBOLS (file, section); + } + else if (section->sh_type == SHT_STRTAB + && streq (name, ".dynstr")) + { + if (dynamic_strings != NULL) + { + error (_("File contains multiple dynamic string tables\n")); + continue; + } + + dynamic_strings = get_data (NULL, file, section->sh_offset, + 1, section->sh_size, _("dynamic strings")); + dynamic_strings_length = section->sh_size; + } + 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 (section->sh_type == SHT_SYMTAB) + CHECK_ENTSIZE (section, i, Sym); + else if (section->sh_type == SHT_GROUP) + CHECK_ENTSIZE_VALUES (section, i, GRP_ENTRY_SIZE, GRP_ENTRY_SIZE); + else if (section->sh_type == SHT_REL) + CHECK_ENTSIZE (section, i, Rel); + else if (section->sh_type == SHT_RELA) + CHECK_ENTSIZE (section, i, Rela); + 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 || do_debug_ranges) + && strneq (name, ".debug_", 7)) + { + name += 7; + + if (do_debugging + || (do_debug_info && streq (name, "info")) + || (do_debug_abbrevs && streq (name, "abbrev")) + || (do_debug_lines && streq (name, "line")) + || (do_debug_pubnames && streq (name, "pubnames")) + || (do_debug_aranges && streq (name, "aranges")) + || (do_debug_ranges && streq (name, "ranges")) + || (do_debug_frames && streq (name, "frame")) + || (do_debug_macinfo && streq (name, "macinfo")) + || (do_debug_str && streq (name, "str")) + || (do_debug_loc && streq (name, "loc")) + ) + request_dump (i, DEBUG_DUMP); + } + /* linkonce section to be combined with .debug_info at link time. */ + else if ((do_debugging || do_debug_info) + && strneq (name, ".gnu.linkonce.wi.", 17)) + request_dump (i, DEBUG_DUMP); + else if (do_debug_frames && streq (name, ".eh_frame")) + 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) + { + if (do_section_details) + { + printf (_(" [Nr] Name\n")); + printf (_(" Type Addr Off Size ES Lk Inf Al\n")); + } + else + printf + (_(" [Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n")); + } + else if (do_wide) + { + if (do_section_details) + { + printf (_(" [Nr] Name\n")); + printf (_(" Type Address Off Size ES Lk Inf Al\n")); + } + else + printf + (_(" [Nr] Name Type Address Off Size ES Flg Lk Inf Al\n")); + } + else + { + if (do_section_details) + { + printf (_(" [Nr] Name\n")); + printf (_(" Type Address Offset Link\n")); + printf (_(" Size EntSize Info Align\n")); + } + else + { + printf (_(" [Nr] Name Type Address Offset\n")); + printf (_(" Size EntSize Flags Link Info Align\n")); + } + } + + if (do_section_details) + printf (_(" Flags\n")); + + for (i = 0, section = section_headers; + i < elf_header.e_shnum; + i++, section++) + { + if (do_section_details) + { + printf (" [%2u] %s\n", + SECTION_HEADER_NUM (i), + SECTION_NAME (section)); + if (is_32bit_elf || do_wide) + printf (" %-15.15s ", + get_section_type_name (section->sh_type)); + } + else + 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); + + if (do_section_details) + fputs (" ", stdout); + else + printf (" %3s ", get_elf_section_flags (section->sh_flags)); + + printf ("%2ld %3lu %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); + } + + if (do_section_details) + fputs (" ", stdout); + else + printf (" %3s ", get_elf_section_flags (section->sh_flags)); + + printf ("%2ld %3lu ", + (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 if (do_section_details) + { + printf (" %-15.15s ", + get_section_type_name (section->sh_type)); + print_vma (section->sh_addr, LONG_HEX); + if ((long) section->sh_offset == section->sh_offset) + printf (" %16.16lx", (unsigned long) section->sh_offset); + else + { + printf (" "); + print_vma (section->sh_offset, LONG_HEX); + } + printf (" %ld\n ", (unsigned long) section->sh_link); + print_vma (section->sh_size, LONG_HEX); + putchar (' '); + print_vma (section->sh_entsize, LONG_HEX); + + printf (" %-16lu %ld\n", + (unsigned long) section->sh_info, + (unsigned long) section->sh_addralign); + } + 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 %3lu %ld\n", + (unsigned long) section->sh_link, + (unsigned long) section->sh_info, + (unsigned long) section->sh_addralign); + } + + if (do_section_details) + printf (" %s\n", get_elf_section_flags (section->sh_flags)); + } + + if (!do_section_details) + 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; +} + +static const char * +get_group_flags (unsigned int flags) +{ + static char buff[32]; + switch (flags) + { + case GRP_COMDAT: + return "COMDAT"; + + default: + snprintf (buff, sizeof (buff), _("[: 0x%x]"), flags); + break; + } + return buff; +} + +static int +process_section_groups (FILE *file) +{ + Elf_Internal_Shdr *section; + unsigned int i; + struct group *group; + Elf_Internal_Shdr *symtab_sec, *strtab_sec; + Elf_Internal_Sym *symtab; + char *strtab; + size_t strtab_size; + + /* Don't process section groups unless needed. */ + if (!do_unwind && !do_section_groups) + return 1; + + if (elf_header.e_shnum == 0) + { + if (do_section_groups) + printf (_("\nThere are no sections in this file.\n")); + + return 1; + } + + if (section_headers == NULL) + { + error (_("Section headers are not available!\n")); + abort (); + } + + section_headers_groups = calloc (elf_header.e_shnum, + sizeof (struct group *)); + + if (section_headers_groups == NULL) + { + error (_("Out of memory\n")); + return 0; + } + + /* Scan the sections for the group section. */ + group_count = 0; + for (i = 0, section = section_headers; + i < elf_header.e_shnum; + i++, section++) + if (section->sh_type == SHT_GROUP) + group_count++; + + if (group_count == 0) + { + if (do_section_groups) + printf (_("\nThere are no section groups in this file.\n")); + + return 1; + } + + section_groups = calloc (group_count, sizeof (struct group)); + + if (section_groups == NULL) + { + error (_("Out of memory\n")); + return 0; + } + + symtab_sec = NULL; + strtab_sec = NULL; + symtab = NULL; + strtab = NULL; + strtab_size = 0; + for (i = 0, section = section_headers, group = section_groups; + i < elf_header.e_shnum; + i++, section++) + { + if (section->sh_type == SHT_GROUP) + { + char *name = SECTION_NAME (section); + char *group_name; + unsigned char *start, *indices; + unsigned int entry, j, size; + Elf_Internal_Shdr *sec; + Elf_Internal_Sym *sym; + + /* Get the symbol table. */ + if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum + || ((sec = SECTION_HEADER (section->sh_link))->sh_type + != SHT_SYMTAB)) + { + error (_("Bad sh_link in group section `%s'\n"), name); + continue; + } + + if (symtab_sec != sec) + { + symtab_sec = sec; + if (symtab) + free (symtab); + symtab = GET_ELF_SYMBOLS (file, symtab_sec); + } + + sym = symtab + section->sh_info; + + if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + bfd_vma sec_index = SECTION_HEADER_INDEX (sym->st_shndx); + if (sec_index == 0) + { + error (_("Bad sh_info in group section `%s'\n"), name); + continue; + } + + group_name = SECTION_NAME (section_headers + sec_index); + strtab_sec = NULL; + if (strtab) + free (strtab); + strtab = NULL; + strtab_size = 0; + } + else + { + /* Get the string table. */ + if (SECTION_HEADER_INDEX (symtab_sec->sh_link) + >= elf_header.e_shnum) + { + strtab_sec = NULL; + if (strtab) + free (strtab); + strtab = NULL; + strtab_size = 0; + } + else if (strtab_sec + != (sec = SECTION_HEADER (symtab_sec->sh_link))) + { + strtab_sec = sec; + if (strtab) + free (strtab); + strtab = get_data (NULL, file, strtab_sec->sh_offset, + 1, strtab_sec->sh_size, + _("string table")); + strtab_size = strtab != NULL ? strtab_sec->sh_size : 0; + } + group_name = sym->st_name < strtab_size + ? strtab + sym->st_name : ""; + } + + start = get_data (NULL, file, section->sh_offset, + 1, section->sh_size, _("section data")); + + indices = start; + size = (section->sh_size / section->sh_entsize) - 1; + entry = byte_get (indices, 4); + indices += 4; + + if (do_section_groups) + { + printf ("\n%s group section [%5u] `%s' [%s] contains %u sections:\n", + get_group_flags (entry), i, name, group_name, size); + + printf (_(" [Index] Name\n")); + } + + group->group_index = i; + + for (j = 0; j < size; j++) + { + struct group_list *g; + + entry = byte_get (indices, 4); + indices += 4; + + if (SECTION_HEADER_INDEX (entry) >= elf_header.e_shnum) + { + error (_("section [%5u] in group section [%5u] > maximum section [%5u]\n"), + entry, i, elf_header.e_shnum - 1); + continue; + } + else if (entry >= SHN_LORESERVE && entry <= SHN_HIRESERVE) + { + error (_("invalid section [%5u] in group section [%5u]\n"), + entry, i); + continue; + } + + if (section_headers_groups [SECTION_HEADER_INDEX (entry)] + != NULL) + { + if (entry) + { + error (_("section [%5u] in group section [%5u] already in group section [%5u]\n"), + entry, i, + section_headers_groups [SECTION_HEADER_INDEX (entry)]->group_index); + continue; + } + else + { + /* Intel C/C++ compiler may put section 0 in a + section group. We just warn it the first time + and ignore it afterwards. */ + static int warned = 0; + if (!warned) + { + error (_("section 0 in group section [%5u]\n"), + section_headers_groups [SECTION_HEADER_INDEX (entry)]->group_index); + warned++; + } + } + } + + section_headers_groups [SECTION_HEADER_INDEX (entry)] + = group; + + if (do_section_groups) + { + sec = SECTION_HEADER (entry); + printf (" [%5u] %s\n", entry, SECTION_NAME (sec)); + } + + g = xmalloc (sizeof (struct group_list)); + g->section_index = entry; + g->next = group->root; + group->root = g; + } + + if (start) + free (start); + + group++; + } + } + + if (symtab) + free (symtab); + if (strtab) + free (strtab); + return 1; +} + +static 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) +{ + 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, + offset_from_vma (file, rel_offset, rel_size), + rel_size, + dynamic_symbols, num_dynamic_syms, + dynamic_strings, dynamic_strings_length, 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; + int is_rela; + + 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)); + + is_rela = section->sh_type == SHT_RELA; + + if (section->sh_link + && SECTION_HEADER_INDEX (section->sh_link) + < elf_header.e_shnum) + { + Elf_Internal_Shdr *symsec; + Elf_Internal_Sym *symtab; + unsigned long nsyms; + unsigned long strtablen = 0; + char *strtab = NULL; + + symsec = SECTION_HEADER (section->sh_link); + if (symsec->sh_type != SHT_SYMTAB + && symsec->sh_type != SHT_DYNSYM) + continue; + + nsyms = symsec->sh_size / symsec->sh_entsize; + symtab = GET_ELF_SYMBOLS (file, symsec); + + if (symtab == NULL) + continue; + + if (SECTION_HEADER_INDEX (symsec->sh_link) + < elf_header.e_shnum) + { + strsec = SECTION_HEADER (symsec->sh_link); + + strtab = get_data (NULL, file, strsec->sh_offset, + 1, strsec->sh_size, + _("string table")); + strtablen = strtab == NULL ? 0 : strsec->sh_size; + } + + dump_relocations (file, rel_offset, rel_size, + symtab, nsyms, strtab, strtablen, is_rela); + if (strtab) + free (strtab); + free (symtab); + } + else + dump_relocations (file, rel_offset, rel_size, + NULL, 0, NULL, 0, is_rela); + + found = 1; + } + } + + if (! found) + printf (_("\nThere are no relocations in this file.\n")); + } + + return 1; +} + +/* Process the unwind section. */ + +#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; + }; + +#define ABSADDR(a) \ + ((a).section \ + ? section_headers [(a).section].sh_addr + (a).offset \ + : (a).offset) + +struct ia64_unw_aux_info + { + struct ia64_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 (Elf_Internal_Sym *symtab, + unsigned long nsyms, + const char *strtab, + unsigned long strtab_size, + struct absaddr addr, + const char **symname, + bfd_vma *offset) +{ + bfd_vma dist = 0x100000; + Elf_Internal_Sym *sym, *best = NULL; + unsigned long i; + + for (i = 0, sym = symtab; i < 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 >= strtab_size + ? "" : strtab + best->st_name); + *offset = dist; + return; + } + *symname = NULL; + *offset = addr.offset; +} + +static void +dump_ia64_unwind (struct ia64_unw_aux_info *aux) +{ + struct ia64_unw_table_entry *tp; + int in_body; + + 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->symtab, aux->nsyms, aux->strtab, + aux->strtab_size, 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 + (ABSADDR (tp->info) - aux->info_addr); + stamp = byte_get ((unsigned char *) head, sizeof (stamp)); + + 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) (eh_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 + eh_addr_size * UNW_LENGTH (stamp);) + dp = unw_decode (dp, in_body, & in_body); + } +} + +static int +slurp_ia64_unwind_table (FILE *file, + struct ia64_unw_aux_info *aux, + Elf_Internal_Shdr *sec) +{ + unsigned long size, nrelas, i; + Elf_Internal_Phdr *seg; + struct ia64_unw_table_entry *tep; + Elf_Internal_Shdr *relsec; + Elf_Internal_Rela *rela, *rp; + unsigned char *table, *tp; + Elf_Internal_Sym *sym; + const char *relname; + + /* First, find the starting address of the segment that includes + this section: */ + + if (elf_header.e_phnum) + { + if (! get_program_headers (file)) + return 0; + + for (seg = program_headers; + seg < program_headers + 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; + } + } + } + + /* Second, build the unwind table from the contents of the unwind section: */ + size = sec->sh_size; + table = get_data (NULL, file, sec->sh_offset, 1, size, _("unwind table")); + if (!table) + return 0; + + aux->table = xcmalloc (size / (3 * eh_addr_size), sizeof (aux->table[0])); + tep = aux->table; + for (tp = table; tp < table + size; tp += 3 * eh_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_GET ((unsigned char *) tp + 0); + tep->end.offset = BYTE_GET ((unsigned char *) tp + 8); + tep->info.offset = BYTE_GET ((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_INDEX (relsec->sh_info) >= elf_header.e_shnum + || 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); + } + else + { + relname = elf_ia64_reloc_type (ELF64_R_TYPE (rp->r_info)); + sym = aux->symtab + ELF64_R_SYM (rp->r_info); + } + + if (! strneq (relname, "R_IA64_SEGREL", 13)) + { + warn (_("Skipping unexpected relocation type %s\n"), relname); + continue; + } + + i = rp->r_offset / (3 * eh_addr_size); + + switch (rp->r_offset/eh_addr_size % 3) + { + case 0: + aux->table[i].start.section = sym->st_shndx; + aux->table[i].start.offset += rp->r_addend + sym->st_value; + break; + case 1: + aux->table[i].end.section = sym->st_shndx; + aux->table[i].end.offset += rp->r_addend + sym->st_value; + break; + case 2: + aux->table[i].info.section = sym->st_shndx; + aux->table[i].info.offset += rp->r_addend + sym->st_value; + break; + default: + break; + } + } + + free (rela); + } + + aux->table_len = size / (3 * eh_addr_size); + return 1; +} + +static int +ia64_process_unwind (FILE *file) +{ + Elf_Internal_Shdr *sec, *unwsec = NULL, *strsec; + unsigned long i, unwcount = 0, unwstart = 0; + struct ia64_unw_aux_info aux; + + memset (& aux, 0, sizeof (aux)); + + for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec) + { + if (sec->sh_type == SHT_SYMTAB + && SECTION_HEADER_INDEX (sec->sh_link) < elf_header.e_shnum) + { + aux.nsyms = sec->sh_size / sec->sh_entsize; + aux.symtab = GET_ELF_SYMBOLS (file, sec); + + strsec = SECTION_HEADER (sec->sh_link); + aux.strtab = get_data (NULL, file, strsec->sh_offset, + 1, strsec->sh_size, _("string table")); + aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0; + } + 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 ((unwsec->sh_flags & SHF_GROUP) != 0) + { + /* We need to find which section group it is in. */ + struct group_list *g = section_headers_groups [i]->root; + + for (; g != NULL; g = g->next) + { + sec = SECTION_HEADER (g->section_index); + + if (streq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info)) + break; + } + + if (g == NULL) + i = elf_header.e_shnum; + } + else if (strneq (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind_once, len)) + { + /* .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 (strneq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info_once, len2) + && streq (SECTION_NAME (sec) + len2, suffix)) + 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 (strneq (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind, len)) + suffix = SECTION_NAME (unwsec) + len; + for (i = 0, sec = section_headers; i < elf_header.e_shnum; + ++i, ++sec) + if (strneq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info, len2) + && streq (SECTION_NAME (sec) + len2, suffix)) + 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 = get_data (NULL, file, sec->sh_offset, 1, 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 * eh_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; +} + +struct hppa_unw_aux_info + { + struct hppa_unw_table_entry + { + struct absaddr start; + struct absaddr end; + unsigned int Cannot_unwind:1; /* 0 */ + unsigned int Millicode:1; /* 1 */ + unsigned int Millicode_save_sr0:1; /* 2 */ + unsigned int Region_description:2; /* 3..4 */ + unsigned int reserved1:1; /* 5 */ + unsigned int Entry_SR:1; /* 6 */ + unsigned int Entry_FR:4; /* number saved */ /* 7..10 */ + unsigned int Entry_GR:5; /* number saved */ /* 11..15 */ + unsigned int Args_stored:1; /* 16 */ + unsigned int Variable_Frame:1; /* 17 */ + unsigned int Separate_Package_Body:1; /* 18 */ + unsigned int Frame_Extension_Millicode:1; /* 19 */ + unsigned int Stack_Overflow_Check:1; /* 20 */ + unsigned int Two_Instruction_SP_Increment:1; /* 21 */ + unsigned int Ada_Region:1; /* 22 */ + unsigned int cxx_info:1; /* 23 */ + unsigned int cxx_try_catch:1; /* 24 */ + unsigned int sched_entry_seq:1; /* 25 */ + unsigned int reserved2:1; /* 26 */ + unsigned int Save_SP:1; /* 27 */ + unsigned int Save_RP:1; /* 28 */ + unsigned int Save_MRP_in_frame:1; /* 29 */ + unsigned int extn_ptr_defined:1; /* 30 */ + unsigned int Cleanup_defined:1; /* 31 */ + + unsigned int MPE_XL_interrupt_marker:1; /* 0 */ + unsigned int HP_UX_interrupt_marker:1; /* 1 */ + unsigned int Large_frame:1; /* 2 */ + unsigned int Pseudo_SP_Set:1; /* 3 */ + unsigned int reserved4:1; /* 4 */ + unsigned int Total_frame_size:27; /* 5..31 */ + } + *table; /* Unwind table. */ + unsigned long table_len; /* Length of unwind table. */ + 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 +dump_hppa_unwind (struct hppa_unw_aux_info *aux) +{ + struct hppa_unw_table_entry *tp; + + for (tp = aux->table; tp < aux->table + aux->table_len; ++tp) + { + bfd_vma offset; + const char *procname; + + find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab, + aux->strtab_size, 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 ("]\n\t"); + +#define PF(_m) if (tp->_m) printf (#_m " "); +#define PV(_m) if (tp->_m) printf (#_m "=%d ", tp->_m); + PF(Cannot_unwind); + PF(Millicode); + PF(Millicode_save_sr0); + /* PV(Region_description); */ + PF(Entry_SR); + PV(Entry_FR); + PV(Entry_GR); + PF(Args_stored); + PF(Variable_Frame); + PF(Separate_Package_Body); + PF(Frame_Extension_Millicode); + PF(Stack_Overflow_Check); + PF(Two_Instruction_SP_Increment); + PF(Ada_Region); + PF(cxx_info); + PF(cxx_try_catch); + PF(sched_entry_seq); + PF(Save_SP); + PF(Save_RP); + PF(Save_MRP_in_frame); + PF(extn_ptr_defined); + PF(Cleanup_defined); + PF(MPE_XL_interrupt_marker); + PF(HP_UX_interrupt_marker); + PF(Large_frame); + PF(Pseudo_SP_Set); + PV(Total_frame_size); +#undef PF +#undef PV + } + + printf ("\n"); +} + +static int +slurp_hppa_unwind_table (FILE *file, + struct hppa_unw_aux_info *aux, + Elf_Internal_Shdr *sec) +{ + unsigned long size, unw_ent_size, nentries, nrelas, i; + Elf_Internal_Phdr *seg; + struct hppa_unw_table_entry *tep; + Elf_Internal_Shdr *relsec; + Elf_Internal_Rela *rela, *rp; + unsigned char *table, *tp; + Elf_Internal_Sym *sym; + const char *relname; + + /* First, find the starting address of the segment that includes + this section. */ + + if (elf_header.e_phnum) + { + if (! get_program_headers (file)) + return 0; + + for (seg = program_headers; + seg < program_headers + 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; + } + } + } + + /* Second, build the unwind table from the contents of the unwind + section. */ + size = sec->sh_size; + table = get_data (NULL, file, sec->sh_offset, 1, size, _("unwind table")); + if (!table) + return 0; + + unw_ent_size = 16; + nentries = size / unw_ent_size; + size = unw_ent_size * nentries; + + tep = aux->table = xcmalloc (nentries, sizeof (aux->table[0])); + + for (tp = table; tp < table + size; tp += unw_ent_size, ++tep) + { + unsigned int tmp1, tmp2; + + tep->start.section = SHN_UNDEF; + tep->end.section = SHN_UNDEF; + + tep->start.offset = byte_get ((unsigned char *) tp + 0, 4); + tep->end.offset = byte_get ((unsigned char *) tp + 4, 4); + tmp1 = byte_get ((unsigned char *) tp + 8, 4); + tmp2 = byte_get ((unsigned char *) tp + 12, 4); + + tep->start.offset += aux->seg_base; + tep->end.offset += aux->seg_base; + + tep->Cannot_unwind = (tmp1 >> 31) & 0x1; + tep->Millicode = (tmp1 >> 30) & 0x1; + tep->Millicode_save_sr0 = (tmp1 >> 29) & 0x1; + tep->Region_description = (tmp1 >> 27) & 0x3; + tep->reserved1 = (tmp1 >> 26) & 0x1; + tep->Entry_SR = (tmp1 >> 25) & 0x1; + tep->Entry_FR = (tmp1 >> 21) & 0xf; + tep->Entry_GR = (tmp1 >> 16) & 0x1f; + tep->Args_stored = (tmp1 >> 15) & 0x1; + tep->Variable_Frame = (tmp1 >> 14) & 0x1; + tep->Separate_Package_Body = (tmp1 >> 13) & 0x1; + tep->Frame_Extension_Millicode = (tmp1 >> 12) & 0x1; + tep->Stack_Overflow_Check = (tmp1 >> 11) & 0x1; + tep->Two_Instruction_SP_Increment = (tmp1 >> 10) & 0x1; + tep->Ada_Region = (tmp1 >> 9) & 0x1; + tep->cxx_info = (tmp1 >> 8) & 0x1; + tep->cxx_try_catch = (tmp1 >> 7) & 0x1; + tep->sched_entry_seq = (tmp1 >> 6) & 0x1; + tep->reserved2 = (tmp1 >> 5) & 0x1; + tep->Save_SP = (tmp1 >> 4) & 0x1; + tep->Save_RP = (tmp1 >> 3) & 0x1; + tep->Save_MRP_in_frame = (tmp1 >> 2) & 0x1; + tep->extn_ptr_defined = (tmp1 >> 1) & 0x1; + tep->Cleanup_defined = tmp1 & 0x1; + + tep->MPE_XL_interrupt_marker = (tmp2 >> 31) & 0x1; + tep->HP_UX_interrupt_marker = (tmp2 >> 30) & 0x1; + tep->Large_frame = (tmp2 >> 29) & 0x1; + tep->Pseudo_SP_Set = (tmp2 >> 28) & 0x1; + tep->reserved4 = (tmp2 >> 27) & 0x1; + tep->Total_frame_size = tmp2 & 0x7ffffff; + } + 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_INDEX (relsec->sh_info) >= elf_header.e_shnum + || 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_hppa_reloc_type (ELF32_R_TYPE (rp->r_info)); + sym = aux->symtab + ELF32_R_SYM (rp->r_info); + } + else + { + relname = elf_hppa_reloc_type (ELF64_R_TYPE (rp->r_info)); + sym = aux->symtab + ELF64_R_SYM (rp->r_info); + } + + /* R_PARISC_SEGREL32 or R_PARISC_SEGREL64. */ + if (strncmp (relname, "R_PARISC_SEGREL", 15) != 0) + { + warn (_("Skipping unexpected relocation type %s\n"), relname); + continue; + } + + i = rp->r_offset / unw_ent_size; + + switch ((rp->r_offset % unw_ent_size) / eh_addr_size) + { + case 0: + aux->table[i].start.section = sym->st_shndx; + aux->table[i].start.offset += sym->st_value + rp->r_addend; + break; + case 1: + aux->table[i].end.section = sym->st_shndx; + aux->table[i].end.offset += sym->st_value + rp->r_addend; + break; + default: + break; + } + } + + free (rela); + } + + aux->table_len = nentries; + + return 1; +} + +static int +hppa_process_unwind (FILE *file) +{ + struct hppa_unw_aux_info aux; + Elf_Internal_Shdr *unwsec = NULL; + Elf_Internal_Shdr *strsec; + Elf_Internal_Shdr *sec; + unsigned long i; + + memset (& aux, 0, sizeof (aux)); + + if (string_table == NULL) + return 1; + + for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec) + { + if (sec->sh_type == SHT_SYMTAB + && SECTION_HEADER_INDEX (sec->sh_link) < elf_header.e_shnum) + { + aux.nsyms = sec->sh_size / sec->sh_entsize; + aux.symtab = GET_ELF_SYMBOLS (file, sec); + + strsec = SECTION_HEADER (sec->sh_link); + aux.strtab = get_data (NULL, file, strsec->sh_offset, + 1, strsec->sh_size, _("string table")); + aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0; + } + else if (streq (SECTION_NAME (sec), ".PARISC.unwind")) + unwsec = sec; + } + + if (!unwsec) + printf (_("\nThere are no unwind sections in this file.\n")); + + for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec) + { + if (streq (SECTION_NAME (sec), ".PARISC.unwind")) + { + printf (_("\nUnwind section ")); + printf (_("'%s'"), SECTION_NAME (sec)); + + printf (_(" at offset 0x%lx contains %lu entries:\n"), + (unsigned long) sec->sh_offset, + (unsigned long) (sec->sh_size / (2 * eh_addr_size + 8))); + + slurp_hppa_unwind_table (file, &aux, sec); + if (aux.table_len > 0) + dump_hppa_unwind (&aux); + + if (aux.table) + free ((char *) aux.table); + aux.table = NULL; + } + } + + if (aux.symtab) + free (aux.symtab); + if (aux.strtab) + free ((char *) aux.strtab); + + return 1; +} + +static int +process_unwind (FILE *file) +{ + struct unwind_handler { + int machtype; + int (*handler)(FILE *file); + } handlers[] = { + { EM_IA_64, ia64_process_unwind }, + { EM_PARISC, hppa_process_unwind }, + { 0, 0 } + }; + int i; + + if (!do_unwind) + return 1; + + for (i = 0; handlers[i].handler != NULL; i++) + if (elf_header.e_machine == handlers[i].machtype) + return handlers[i].handler (file); + + printf (_("\nThere are no unwind sections in this file.\n")); + return 1; +} + +static void +dynamic_section_mips_val (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 (VALID_DYNAMIC_NAME (entry->d_un.d_val)) + printf ("Interface Version: %s\n", GET_DYNAMIC_NAME (entry->d_un.d_val)); + else + printf ("\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); + snprintf (timebuf, sizeof (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_section_parisc_val (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" }, + { DT_HP_GST, "HP_GST" }, + { DT_HP_SHLIB_FIXED, "HP_SHLIB_FIXED" }, + { DT_HP_MERGE_SHLIB_SEG, "HP_MERGE_SHLIB_SEG" }, + { DT_HP_NODELETE, "HP_NODELETE" }, + { DT_HP_GROUP, "HP_GROUP" }, + { DT_HP_PROTECT_LINKAGE_TABLE, "HP_PROTECT_LINKAGE_TABLE" } + }; + 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_section_ia64_val (Elf_Internal_Dyn *entry) +{ + switch (entry->d_tag) + { + case DT_IA_64_PLT_RESERVE: + /* First 3 slots reserved. */ + print_vma (entry->d_un.d_ptr, PREFIX_HEX); + printf (" -- "); + print_vma (entry->d_un.d_ptr + (3 * 8), PREFIX_HEX); + break; + + default: + print_vma (entry->d_un.d_ptr, PREFIX_HEX); + break; + } + putchar ('\n'); +} + +static int +get_32bit_dynamic_section (FILE *file) +{ + Elf32_External_Dyn *edyn, *ext; + Elf_Internal_Dyn *entry; + + edyn = get_data (NULL, file, dynamic_addr, 1, dynamic_size, + _("dynamic section")); + if (!edyn) + return 0; + +/* SGI's ELF has more than one section in the DYNAMIC segment, and we + might not have the luxury of section headers. Look for the DT_NULL + terminator to determine the number of entries. */ + for (ext = edyn, dynamic_nent = 0; + (char *) ext < (char *) edyn + dynamic_size; + ext++) + { + dynamic_nent++; + if (BYTE_GET (ext->d_tag) == DT_NULL) + break; + } + + dynamic_section = cmalloc (dynamic_nent, sizeof (*entry)); + if (dynamic_section == NULL) + { + error (_("Out of memory\n")); + free (edyn); + return 0; + } + + for (ext = edyn, entry = dynamic_section; + entry < dynamic_section + dynamic_nent; + ext++, entry++) + { + entry->d_tag = BYTE_GET (ext->d_tag); + entry->d_un.d_val = BYTE_GET (ext->d_un.d_val); + } + + free (edyn); + + return 1; +} + +static int +get_64bit_dynamic_section (FILE *file) +{ + Elf64_External_Dyn *edyn, *ext; + Elf_Internal_Dyn *entry; + + edyn = get_data (NULL, file, dynamic_addr, 1, dynamic_size, + _("dynamic section")); + if (!edyn) + return 0; + +/* SGI's ELF has more than one section in the DYNAMIC segment, and we + might not have the luxury of section headers. Look for the DT_NULL + terminator to determine the number of entries. */ + for (ext = edyn, dynamic_nent = 0; + (char *) ext < (char *) edyn + dynamic_size; + ext++) + { + dynamic_nent++; + if (BYTE_GET (ext->d_tag) == DT_NULL) + break; + } + + dynamic_section = cmalloc (dynamic_nent, sizeof (*entry)); + if (dynamic_section == NULL) + { + error (_("Out of memory\n")); + free (edyn); + return 0; + } + + for (ext = edyn, entry = dynamic_section; + entry < dynamic_section + dynamic_nent; + ext++, entry++) + { + entry->d_tag = BYTE_GET (ext->d_tag); + entry->d_un.d_val = BYTE_GET (ext->d_un.d_val); + } + + free (edyn); + + return 1; +} + +static void +print_dynamic_flags (bfd_vma flags) +{ + int first = 1; + + while (flags) + { + bfd_vma flag; + + flag = flags & - flags; + flags &= ~ flag; + + if (first) + first = 0; + else + putc (' ', stdout); + + switch (flag) + { + case DF_ORIGIN: fputs ("ORIGIN", stdout); break; + case DF_SYMBOLIC: fputs ("SYMBOLIC", stdout); break; + case DF_TEXTREL: fputs ("TEXTREL", stdout); break; + case DF_BIND_NOW: fputs ("BIND_NOW", stdout); break; + case DF_STATIC_TLS: fputs ("STATIC_TLS", stdout); break; + default: fputs ("unknown", stdout); break; + } + } + puts (""); +} + +/* Parse and display the contents of the dynamic section. */ + +static int +process_dynamic_section (FILE *file) +{ + Elf_Internal_Dyn *entry; + + if (dynamic_size == 0) + { + if (do_dynamic) + printf (_("\nThere is no dynamic section in this file.\n")); + + return 1; + } + + if (is_32bit_elf) + { + if (! get_32bit_dynamic_section (file)) + return 0; + } + else if (! get_64bit_dynamic_section (file)) + return 0; + + /* Find the appropriate symbol table. */ + if (dynamic_symbols == NULL) + { + for (entry = dynamic_section; + entry < dynamic_section + dynamic_nent; + ++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 = offset_from_vma (file, entry->d_un.d_val, 0); + + if (archive_file_offset != 0) + section.sh_size = archive_file_size - section.sh_offset; + else + { + 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 (entry = dynamic_section; + entry < dynamic_section + dynamic_nent; + ++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 = offset_from_vma (file, entry->d_un.d_val, 0); + + if (archive_file_offset != 0) + str_tab_len = archive_file_size - offset; + else + { + 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 = get_data (NULL, file, offset, 1, str_tab_len, + _("dynamic string table")); + dynamic_strings_length = str_tab_len; + break; + } + } + + /* And find the syminfo section if available. */ + if (dynamic_syminfo == NULL) + { + unsigned long syminsz = 0; + + for (entry = dynamic_section; + entry < dynamic_section + dynamic_nent; + ++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 = offset_from_vma (file, entry->d_un.d_val, + syminsz); + } + + if (dynamic_syminfo_offset != 0 && syminsz != 0) + { + Elf_External_Syminfo *extsyminfo, *extsym; + Elf_Internal_Syminfo *syminfo; + + /* There is a syminfo section. Read the data. */ + extsyminfo = get_data (NULL, file, dynamic_syminfo_offset, 1, + syminsz, _("symbol information")); + if (!extsyminfo) + return 0; + + dynamic_syminfo = malloc (syminsz); + if (dynamic_syminfo == NULL) + { + error (_("Out of memory\n")); + return 0; + } + + dynamic_syminfo_nent = syminsz / sizeof (Elf_External_Syminfo); + for (syminfo = dynamic_syminfo, extsym = extsyminfo; + syminfo < dynamic_syminfo + dynamic_syminfo_nent; + ++syminfo, ++extsym) + { + syminfo->si_boundto = BYTE_GET (extsym->si_boundto); + syminfo->si_flags = BYTE_GET (extsym->si_flags); + } + + free (extsyminfo); + } + } + + if (do_dynamic && dynamic_addr) + printf (_("\nDynamic section at offset 0x%lx contains %u entries:\n"), + dynamic_addr, dynamic_nent); + if (do_dynamic) + printf (_(" Tag Type Name/Value\n")); + + for (entry = dynamic_section; + entry < dynamic_section + dynamic_nent; + 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) + print_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 (VALID_DYNAMIC_NAME (entry->d_un.d_val)) + printf (": [%s]\n", GET_DYNAMIC_NAME (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 (VALID_DYNAMIC_NAME (entry->d_un.d_val)) + name = GET_DYNAMIC_NAME (entry->d_un.d_val); + else + name = NULL; + + if (name) + { + switch (entry->d_tag) + { + case DT_NEEDED: + printf (_("Shared library: [%s]"), name); + + if (streq (name, program_interpreter)) + 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 (entry->d_tag == DT_USED + && VALID_DYNAMIC_NAME (entry->d_un.d_val)) + { + char *name = GET_DYNAMIC_NAME (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_section_mips_val (entry); + break; + case EM_PARISC: + dynamic_section_parisc_val (entry); + break; + case EM_IA_64: + dynamic_section_ia64_val (entry); + break; + default: + print_vma (entry->d_un.d_val, PREFIX_HEX); + putchar ('\n'); + } + } + break; + } + } + + return 1; +} + +static char * +get_ver_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) +{ + 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_HEADER_INDEX (section->sh_link) + < elf_header.e_shnum + ? SECTION_NAME (SECTION_HEADER (section->sh_link)) + : ""); + + edefs = get_data (NULL, file, section->sh_offset, 1, + 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 (VALID_DYNAMIC_NAME (aux.vda_name)) + printf (_("Name: %s\n"), GET_DYNAMIC_NAME (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 (VALID_DYNAMIC_NAME (aux.vda_name)) + printf (_(" %#06x: Parent %d: %s\n"), + isum, j, GET_DYNAMIC_NAME (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_HEADER_INDEX (section->sh_link) + < elf_header.e_shnum + ? SECTION_NAME (SECTION_HEADER (section->sh_link)) + : ""); + + eneed = get_data (NULL, file, section->sh_offset, 1, + 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 (VALID_DYNAMIC_NAME (ent.vn_file)) + printf (_(" File: %s"), GET_DYNAMIC_NAME (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 (VALID_DYNAMIC_NAME (aux.vna_name)) + printf (_(" %#06x: Name: %s"), + isum, GET_DYNAMIC_NAME (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; + long off; + + if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum) + break; + + link_section = SECTION_HEADER (section->sh_link); + total = section->sh_size / sizeof (Elf_External_Versym); + + if (SECTION_HEADER_INDEX (link_section->sh_link) + >= elf_header.e_shnum) + break; + + found = 1; + + symbols = GET_ELF_SYMBOLS (file, link_section); + + string_sec = SECTION_HEADER (link_section->sh_link); + + strtab = get_data (NULL, file, string_sec->sh_offset, 1, + 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)); + + off = offset_from_vma (file, + version_info[DT_VERSIONTAGIDX (DT_VERSYM)], + total * sizeof (short)); + edata = get_data (NULL, file, off, total, sizeof (short), + _("version symbol data")); + if (!edata) + { + free (strtab); + break; + } + + data = cmalloc (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_INDEX (symbols[cnt + j].st_shndx) + >= elf_header.e_shnum + || 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 = offset_from_vma + (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)], + sizeof (Elf_External_Verneed)); + + do + { + Elf_Internal_Vernaux ivna; + Elf_External_Verneed evn; + Elf_External_Vernaux evna; + unsigned long a_off; + + get_data (&evn, file, offset, sizeof (evn), 1, + _("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), + 1, _("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 = offset_from_vma + (file, version_info[DT_VERSIONTAGIDX (DT_VERDEF)], + sizeof evd); + + do + { + get_data (&evd, file, offset, sizeof (evd), 1, + _("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), 1, + _("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 (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) + snprintf (buff, sizeof (buff), _(": %d"), + binding); + else if (binding >= STB_LOOS && binding <= STB_HIOS) + snprintf (buff, sizeof (buff), _(": %d"), binding); + else + snprintf (buff, sizeof (buff), _(": %d"), binding); + return buff; + } +} + +static const char * +get_symbol_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"; + + snprintf (buff, sizeof (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"; + } + + snprintf (buff, sizeof (buff), _(": %d"), type); + } + else + snprintf (buff, sizeof (buff), _(": %d"), type); + return buff; + } +} + +static const char * +get_symbol_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_mips_symbol_other (unsigned int other) +{ + switch (other) + { + case STO_OPTIONAL: return "OPTIONAL"; + case STO_MIPS16: return "MIPS16"; + default: return NULL; + } +} + +static const char * +get_symbol_other (unsigned int other) +{ + const char * result = NULL; + static char buff [32]; + + if (other == 0) + return ""; + + switch (elf_header.e_machine) + { + case EM_MIPS: + result = get_mips_symbol_other (other); + default: + break; + } + + if (result) + return result; + + snprintf (buff, sizeof buff, _(": %x"), other); + return buff; +} + +static const char * +get_symbol_index_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_IA_64_ANSI_COMMON + && elf_header.e_machine == EM_IA_64 + && elf_header.e_ident[EI_OSABI] == ELFOSABI_HPUX) + return "ANSI_COM"; + else if (elf_header.e_machine == EM_X86_64 + && type == SHN_X86_64_LCOMMON) + return "LARGE_COM"; + else 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 bfd_vma * +get_dynamic_data (FILE *file, unsigned int number, unsigned int ent_size) +{ + unsigned char *e_data; + bfd_vma *i_data; + + e_data = cmalloc (number, ent_size); + + if (e_data == NULL) + { + error (_("Out of memory\n")); + return NULL; + } + + if (fread (e_data, ent_size, number, file) != number) + { + error (_("Unable to read in dynamic data\n")); + return NULL; + } + + i_data = cmalloc (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 * ent_size, ent_size); + + free (e_data); + + return i_data; +} + +/* Dump the symbol table. */ +static int +process_symbol_table (FILE *file) +{ + Elf_Internal_Shdr *section; + bfd_vma nbuckets = 0; + bfd_vma nchains = 0; + bfd_vma *buckets = NULL; + bfd_vma *chains = NULL; + + if (! do_syms && !do_histogram) + return 1; + + if (dynamic_info[DT_HASH] && ((do_using_dynamic && dynamic_strings != NULL) + || do_histogram)) + { + unsigned char nb[8]; + unsigned char nc[8]; + int hash_ent_size = 4; + + if ((elf_header.e_machine == EM_ALPHA + || elf_header.e_machine == EM_S390 + || elf_header.e_machine == EM_S390_OLD) + && elf_header.e_ident[EI_CLASS] == ELFCLASS64) + hash_ent_size = 8; + + if (fseek (file, + (archive_file_offset + + offset_from_vma (file, dynamic_info[DT_HASH], + sizeof nb + sizeof nc)), + SEEK_SET)) + { + error (_("Unable to seek to start of dynamic information")); + return 0; + } + + if (fread (nb, hash_ent_size, 1, file) != 1) + { + error (_("Failed to read in number of buckets\n")); + return 0; + } + + if (fread (nc, hash_ent_size, 1, file) != 1) + { + error (_("Failed to read in number of chains\n")); + return 0; + } + + nbuckets = byte_get (nb, hash_ent_size); + nchains = byte_get (nc, hash_ent_size); + + buckets = get_dynamic_data (file, nbuckets, hash_ent_size); + chains = get_dynamic_data (file, nchains, hash_ent_size); + + if (buckets == NULL || chains == NULL) + return 0; + } + + if (do_syms + && dynamic_info[DT_HASH] && do_using_dynamic && dynamic_strings != NULL) + { + unsigned long hn; + bfd_vma 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; + int n; + + psym = dynamic_symbols + si; + + n = print_vma (si, DEC_5); + if (n < 5) + fputs (" " + n, stdout); + printf (" %3lu: ", 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))); + /* Check to see if any other bits in the st_other field are set. + Note - displaying this information disrupts the layout of the + table being generated, but for the moment this case is very rare. */ + if (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other)) + printf (" [%s] ", get_symbol_other (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other))); + printf (" %3.3s ", get_symbol_index_type (psym->st_shndx)); + if (VALID_DYNAMIC_NAME (psym->st_name)) + print_symbol (25, GET_DYNAMIC_NAME (psym->st_name)); + else + printf (" ", 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 = NULL; + unsigned long int strtab_size = 0; + 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; + strtab_size = string_table_length; + } + else if (SECTION_HEADER_INDEX (section->sh_link) < elf_header.e_shnum) + { + Elf_Internal_Shdr *string_sec; + + string_sec = SECTION_HEADER (section->sh_link); + + strtab = get_data (NULL, file, string_sec->sh_offset, + 1, string_sec->sh_size, _("string table")); + strtab_size = strtab != NULL ? string_sec->sh_size : 0; + } + + 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))); + /* Check to see if any other bits in the st_other field are set. + Note - displaying this information disrupts the layout of the + table being generated, but for the moment this case is very rare. */ + if (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other)) + printf (" [%s] ", get_symbol_other (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other))); + printf (" %4s ", get_symbol_index_type (psym->st_shndx)); + print_symbol (25, psym->st_name < strtab_size + ? 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 = offset_from_vma + (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)], + sizeof data + si * sizeof (vers_data)); + + get_data (&data, file, offset + si * sizeof (vers_data), + sizeof (data), 1, _("version data")); + + vers_data = byte_get (data, 2); + + is_nobits = (SECTION_HEADER_INDEX (psym->st_shndx) + < elf_header.e_shnum + && 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 = offset_from_vma + (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)], + sizeof evn); + + do + { + unsigned long vna_off; + + get_data (&evn, file, offset, sizeof (evn), 1, + _("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), 1, + _("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)", + ivna.vna_name < strtab_size + ? 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 = offset_from_vma + (file, + version_info[DT_VERSIONTAGIDX (DT_VERDEF)], + sizeof (Elf_External_Verdef)); + + do + { + Elf_External_Verdef evd; + + get_data (&evd, file, offset, sizeof (evd), + 1, _("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), + 1, _("version def aux")); + + ivda.vda_name = BYTE_GET (evda.vda_name); + + if (psym->st_name != ivda.vda_name) + printf ((vers_data & 0x8000) + ? "@%s" : "@@%s", + ivda.vda_name < strtab_size + ? 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) + { + unsigned long *lengths; + unsigned long *counts; + unsigned long hn; + bfd_vma si; + unsigned long maxlength = 0; + unsigned long nzero_counts = 0; + unsigned long nsyms = 0; + + printf (_("\nHistogram for bucket list length (total of %lu buckets):\n"), + (unsigned long) nbuckets); + printf (_(" Length Number %% of total Coverage\n")); + + lengths = calloc (nbuckets, sizeof (*lengths)); + if (lengths == NULL) + { + error (_("Out of memory")); + return 0; + } + for (hn = 0; hn < nbuckets; ++hn) + { + for (si = buckets[hn]; si > 0 && si < nchains; si = chains[si]) + { + ++nsyms; + if (maxlength < ++lengths[hn]) + ++maxlength; + } + } + + counts = calloc (maxlength + 1, sizeof (*counts)); + if (counts == NULL) + { + error (_("Out of memory")); + return 0; + } + + for (hn = 0; hn < nbuckets; ++hn) + ++counts[lengths[hn]]; + + if (nbuckets > 0) + { + unsigned long i; + printf (" 0 %-10lu (%5.1f%%)\n", + counts[0], (counts[0] * 100.0) / nbuckets); + for (i = 1; i <= maxlength; ++i) + { + nzero_counts += counts[i] * i; + printf ("%7lu %-10lu (%5.1f%%) %5.1f%%\n", + i, counts[i], (counts[i] * 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 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); + if (VALID_DYNAMIC_NAME (dynamic_symbols[i].st_name)) + print_symbol (30, GET_DYNAMIC_NAME (dynamic_symbols[i].st_name)); + else + printf ("", 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_nent + && VALID_DYNAMIC_NAME (dynamic_section[dynamic_syminfo[i].si_boundto].d_un.d_val)) + { + print_symbol (10, GET_DYNAMIC_NAME (dynamic_section[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 int +disassemble_section (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 (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 || section->sh_type == SHT_NOBITS) + { + 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 = get_data (NULL, file, section->sh_offset, 1, 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 < 0x7f) + printf ("%c", k); + else + printf ("."); + } + + putchar ('\n'); + + data += lbytes; + addr += lbytes; + bytes -= lbytes; + } + + free (start); + + return 1; +} + +/* Apply addends of RELA relocations. */ + +static int +debug_apply_rela_addends (void *file, + Elf_Internal_Shdr *section, + unsigned char *start) +{ + Elf_Internal_Shdr *relsec; + unsigned char *end = start + section->sh_size; + /* FIXME: The relocation field size is relocation type dependent. */ + unsigned int reloc_size = 4; + + if (!is_relocatable) + return 1; + + if (section->sh_size < reloc_size) + return 1; + + 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_INDEX (relsec->sh_info) >= elf_header.e_shnum + || SECTION_HEADER (relsec->sh_info) != section + || relsec->sh_size == 0 + || SECTION_HEADER_INDEX (relsec->sh_link) >= elf_header.e_shnum) + 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; + + loc = start + rp->r_offset; + if ((loc + reloc_size) > end) + { + warn (_("skipping invalid relocation offset 0x%lx in section %s\n"), + (unsigned long) rp->r_offset, + SECTION_NAME (section)); + 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 + /* Relocations against object symbols can happen, + eg when referencing a global array. For an + example of this see the _clz.o binary in libgcc.a. */ + && ELF32_ST_TYPE (sym->st_info) != STT_OBJECT) + { + warn (_("skipping unexpected symbol type %s in relocation in section .rela%s\n"), + get_symbol_type (ELF32_ST_TYPE (sym->st_info)), + SECTION_NAME (section)); + continue; + } + } + else + { + /* In MIPS 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_machine == EM_MIPS + && elf_header.e_ident[EI_DATA] != ELFDATA2MSB) + rp->r_info = (((rp->r_info & 0xffffffff) << 32) + | ((rp->r_info >> 56) & 0xff) + | ((rp->r_info >> 40) & 0xff00) + | ((rp->r_info >> 24) & 0xff0000) + | ((rp->r_info >> 8) & 0xff000000)); + + sym = symtab + ELF64_R_SYM (rp->r_info); + + if (ELF64_R_SYM (rp->r_info) != 0 + && ELF64_ST_TYPE (sym->st_info) != STT_SECTION + && ELF64_ST_TYPE (sym->st_info) != STT_OBJECT) + { + warn (_("skipping unexpected symbol type %s in relocation in section .rela.%s\n"), + get_symbol_type (ELF64_ST_TYPE (sym->st_info)), + SECTION_NAME (section)); + continue; + } + } + + byte_put (loc, rp->r_addend, reloc_size); + } + + free (symtab); + free (rela); + break; + } + return 1; +} + +int +load_debug_section (enum dwarf_section_display_enum debug, void *file) +{ + struct dwarf_section *section = &debug_displays [debug].section; + Elf_Internal_Shdr *sec; + char buf [64]; + + /* If it is already loaded, do nothing. */ + if (section->start != NULL) + return 1; + + /* Locate the debug section. */ + sec = find_section (section->name); + if (sec == NULL) + return 0; + + snprintf (buf, sizeof (buf), _("%s section data"), section->name); + section->address = sec->sh_addr; + section->size = sec->sh_size; + section->start = get_data (NULL, file, sec->sh_offset, 1, + sec->sh_size, buf); + + if (debug_displays [debug].relocate) + debug_apply_rela_addends (file, sec, section->start); + + return section->start != NULL; +} + +void +free_debug_section (enum dwarf_section_display_enum debug) +{ + struct dwarf_section *section = &debug_displays [debug].section; + + if (section->start == NULL) + return; + + free ((char *) section->start); + section->start = NULL; + section->address = 0; + section->size = 0; +} + +static int +display_debug_section (Elf_Internal_Shdr *section, FILE *file) +{ + char *name = SECTION_NAME (section); + bfd_size_type length; + int result = 1; + enum dwarf_section_display_enum i; + + length = section->sh_size; + if (length == 0) + { + printf (_("\nSection '%s' has no debugging data.\n"), name); + return 0; + } + + if (strneq (name, ".gnu.linkonce.wi.", 17)) + name = ".debug_info"; + + /* See if we know how to display the contents of this section. */ + for (i = 0; i < max; i++) + if (streq (debug_displays[i].section.name, name)) + { + struct dwarf_section *sec = &debug_displays [i].section; + + if (load_debug_section (i, file)) + { + result &= debug_displays[i].display (sec, file); + + if (i != info && i != abbrev) + free_debug_section (i); + } + + break; + } + + if (i == max) + { + printf (_("Unrecognized debug section: %s\n"), name); + result = 0; + } + + return result; +} + +/* Set DUMP_SECTS for all sections where dumps were requested + based on section name. */ + +static void +initialise_dumps_byname (void) +{ + struct dump_list_entry *cur; + + for (cur = dump_sects_byname; cur; cur = cur->next) + { + unsigned int i; + int any; + + for (i = 0, any = 0; i < elf_header.e_shnum; i++) + if (streq (SECTION_NAME (section_headers + i), cur->name)) + { + request_dump (i, cur->type); + any = 1; + } + + if (!any) + warn (_("Section '%s' was not dumped because it does not exist!\n"), + cur->name); + } +} + +static void +process_section_contents (FILE *file) +{ + Elf_Internal_Shdr *section; + unsigned int i; + + if (! do_dump) + return; + + initialise_dumps_byname (); + + 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); + } + + /* Check to see if the user requested a + dump of a section that does not exist. */ + while (i++ < num_dump_sects) + if (dump_sects[i]) + warn (_("Section %d was not dumped because it does not exist!\n"), i); +} + +static void +process_mips_fpe_exception (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); +} + +/* ARM EABI attributes section. */ +typedef struct +{ + int tag; + const char *name; + /* 0 = special, 1 = string, 2 = uleb123, > 0x80 == table lookup. */ + int type; + const char **table; +} arm_attr_public_tag; + +static const char *arm_attr_tag_CPU_arch[] = + {"Pre-v4", "v4", "v4T", "v5T", "v5TE", "v5TEJ", "v6", "v6KZ", "v6T2", + "v6K", "v7"}; +static const char *arm_attr_tag_ARM_ISA_use[] = {"No", "Yes"}; +static const char *arm_attr_tag_THUMB_ISA_use[] = + {"No", "Thumb-1", "Thumb-2"}; +static const char *arm_attr_tag_VFP_arch[] = {"No", "VFPv1", "VFPv2"}; +static const char *arm_attr_tag_WMMX_arch[] = {"No", "WMMXv1"}; +static const char *arm_attr_tag_NEON_arch[] = {"No", "NEONv1"}; +static const char *arm_attr_tag_ABI_PCS_config[] = + {"None", "Bare platform", "Linux application", "Linux DSO", "PalmOS 2004", + "PalmOS (reserved)", "SymbianOS 2004", "SymbianOS (reserved)"}; +static const char *arm_attr_tag_ABI_PCS_R9_use[] = + {"V6", "SB", "TLS", "Unused"}; +static const char *arm_attr_tag_ABI_PCS_RW_data[] = + {"Absolute", "PC-relative", "SB-relative", "None"}; +static const char *arm_attr_tag_ABI_PCS_RO_DATA[] = + {"Absolute", "PC-relative", "None"}; +static const char *arm_attr_tag_ABI_PCS_GOT_use[] = + {"None", "direct", "GOT-indirect"}; +static const char *arm_attr_tag_ABI_PCS_wchar_t[] = + {"None", "??? 1", "2", "??? 3", "4"}; +static const char *arm_attr_tag_ABI_FP_rounding[] = {"Unused", "Needed"}; +static const char *arm_attr_tag_ABI_FP_denormal[] = {"Unused", "Needed"}; +static const char *arm_attr_tag_ABI_FP_exceptions[] = {"Unused", "Needed"}; +static const char *arm_attr_tag_ABI_FP_user_exceptions[] = {"Unused", "Needed"}; +static const char *arm_attr_tag_ABI_FP_number_model[] = + {"Unused", "Finite", "RTABI", "IEEE 754"}; +static const char *arm_attr_tag_ABI_align8_needed[] = {"No", "Yes", "4-byte"}; +static const char *arm_attr_tag_ABI_align8_preserved[] = + {"No", "Yes, except leaf SP", "Yes"}; +static const char *arm_attr_tag_ABI_enum_size[] = + {"Unused", "small", "int", "forced to int"}; +static const char *arm_attr_tag_ABI_HardFP_use[] = + {"As Tag_VFP_arch", "SP only", "DP only", "SP and DP"}; +static const char *arm_attr_tag_ABI_VFP_args[] = + {"AAPCS", "VFP registers", "custom"}; +static const char *arm_attr_tag_ABI_WMMX_args[] = + {"AAPCS", "WMMX registers", "custom"}; +static const char *arm_attr_tag_ABI_optimization_goals[] = + {"None", "Prefer Speed", "Aggressive Speed", "Prefer Size", + "Aggressive Size", "Prefer Debug", "Aggressive Debug"}; +static const char *arm_attr_tag_ABI_FP_optimization_goals[] = + {"None", "Prefer Speed", "Aggressive Speed", "Prefer Size", + "Aggressive Size", "Prefer Accuracy", "Aggressive Accuracy"}; + +#define LOOKUP(id, name) \ + {id, #name, 0x80 | ARRAY_SIZE(arm_attr_tag_##name), arm_attr_tag_##name} +static arm_attr_public_tag arm_attr_public_tags[] = +{ + {4, "CPU_raw_name", 1, NULL}, + {5, "CPU_name", 1, NULL}, + LOOKUP(6, CPU_arch), + {7, "CPU_arch_profile", 0, NULL}, + LOOKUP(8, ARM_ISA_use), + LOOKUP(9, THUMB_ISA_use), + LOOKUP(10, VFP_arch), + LOOKUP(11, WMMX_arch), + LOOKUP(12, NEON_arch), + LOOKUP(13, ABI_PCS_config), + LOOKUP(14, ABI_PCS_R9_use), + LOOKUP(15, ABI_PCS_RW_data), + LOOKUP(16, ABI_PCS_RO_DATA), + LOOKUP(17, ABI_PCS_GOT_use), + LOOKUP(18, ABI_PCS_wchar_t), + LOOKUP(19, ABI_FP_rounding), + LOOKUP(20, ABI_FP_denormal), + LOOKUP(21, ABI_FP_exceptions), + LOOKUP(22, ABI_FP_user_exceptions), + LOOKUP(23, ABI_FP_number_model), + LOOKUP(24, ABI_align8_needed), + LOOKUP(25, ABI_align8_preserved), + LOOKUP(26, ABI_enum_size), + LOOKUP(27, ABI_HardFP_use), + LOOKUP(28, ABI_VFP_args), + LOOKUP(29, ABI_WMMX_args), + LOOKUP(30, ABI_optimization_goals), + LOOKUP(31, ABI_FP_optimization_goals), + {32, "compatibility", 0, NULL} +}; +#undef LOOKUP + +/* Read an unsigned LEB128 encoded value from p. Set *PLEN to the number of + bytes read. */ +static unsigned int +read_uleb128 (unsigned char *p, unsigned int *plen) +{ + unsigned char c; + unsigned int val; + int shift; + int len; + + val = 0; + shift = 0; + len = 0; + do + { + c = *(p++); + len++; + val |= ((unsigned int)c & 0x7f) << shift; + shift += 7; + } + while (c & 0x80); + + *plen = len; + return val; +} + +static unsigned char * +display_arm_attribute (unsigned char *p) +{ + int tag; + unsigned int len; + int val; + arm_attr_public_tag *attr; + unsigned i; + int type; + + tag = read_uleb128 (p, &len); + p += len; + attr = NULL; + for (i = 0; i < ARRAY_SIZE(arm_attr_public_tags); i++) + { + if (arm_attr_public_tags[i].tag == tag) + { + attr = &arm_attr_public_tags[i]; + break; + } + } + + if (attr) + { + printf (" Tag_%s: ", attr->name); + switch (attr->type) + { + case 0: + switch (tag) + { + case 7: /* Tag_CPU_arch_profile. */ + val = read_uleb128 (p, &len); + p += len; + switch (val) + { + case 0: printf ("None\n"); break; + case 'A': printf ("Application\n"); break; + case 'R': printf ("Realtime\n"); break; + case 'M': printf ("Microcontroller\n"); break; + default: printf ("??? (%d)\n", val); break; + } + break; + + case 32: /* Tag_compatibility. */ + val = read_uleb128 (p, &len); + p += len; + printf ("flag = %d, vendor = %s\n", val, p); + p += strlen((char *)p) + 1; + break; + + default: + abort(); + } + return p; + + case 1: + case 2: + type = attr->type; + break; + + default: + assert (attr->type & 0x80); + val = read_uleb128 (p, &len); + p += len; + type = attr->type & 0x7f; + if (val >= type) + printf ("??? (%d)\n", val); + else + printf ("%s\n", attr->table[val]); + return p; + } + } + else + { + if (tag & 1) + type = 1; /* String. */ + else + type = 2; /* uleb128. */ + printf (" Tag_unknown_%d: ", tag); + } + + if (type == 1) + { + printf ("\"%s\"\n", p); + p += strlen((char *)p) + 1; + } + else + { + val = read_uleb128 (p, &len); + p += len; + printf ("%d (0x%x)\n", val, val); + } + + return p; +} + +static int +process_arm_specific (FILE *file) +{ + Elf_Internal_Shdr *sect; + unsigned char *contents; + unsigned char *p; + unsigned char *end; + bfd_vma section_len; + bfd_vma len; + unsigned i; + + /* Find the section header so that we get the size. */ + for (i = 0, sect = section_headers; + i < elf_header.e_shnum; + i++, sect++) + { + if (sect->sh_type != SHT_ARM_ATTRIBUTES) + continue; + + contents = get_data (NULL, file, sect->sh_offset, 1, sect->sh_size, + _("attributes")); + + if (!contents) + continue; + p = contents; + if (*p == 'A') + { + len = sect->sh_size - 1; + p++; + while (len > 0) + { + int namelen; + bfd_boolean public_section; + + section_len = byte_get (p, 4); + p += 4; + if (section_len > len) + { + printf (_("ERROR: Bad section length (%d > %d)\n"), + (int)section_len, (int)len); + section_len = len; + } + len -= section_len; + printf ("Attribute Section: %s\n", p); + if (strcmp ((char *)p, "aeabi") == 0) + public_section = TRUE; + else + public_section = FALSE; + namelen = strlen ((char *)p) + 1; + p += namelen; + section_len -= namelen + 4; + while (section_len > 0) + { + int tag = *(p++); + int val; + bfd_vma size; + size = byte_get (p, 4); + if (size > section_len) + { + printf (_("ERROR: Bad subsection length (%d > %d)\n"), + (int)size, (int)section_len); + size = section_len; + } + section_len -= size; + end = p + size - 1; + p += 4; + switch (tag) + { + case 1: + printf ("File Attributes\n"); + break; + case 2: + printf ("Section Attributes:"); + goto do_numlist; + case 3: + printf ("Symbol Attributes:"); + do_numlist: + for (;;) + { + unsigned int i; + val = read_uleb128 (p, &i); + p += i; + if (val == 0) + break; + printf (" %d", val); + } + printf ("\n"); + break; + default: + printf ("Unknown tag: %d\n", tag); + public_section = FALSE; + break; + } + if (public_section) + { + while (p < end) + p = display_arm_attribute(p); + } + else + { + /* ??? Do something sensible, like dump hex. */ + printf (" Unknown section contexts\n"); + p = end; + } + } + } + } + else + { + printf (_("Unknown format '%c'\n"), *p); + } + + free(contents); + } + return 1; +} + +static int +process_mips_specific (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_section == NULL) + /* No information available. */ + return 0; + + for (entry = dynamic_section; entry->d_tag != DT_NULL; ++entry) + switch (entry->d_tag) + { + case DT_MIPS_LIBLIST: + liblist_offset + = offset_from_vma (file, entry->d_un.d_val, + liblistno * sizeof (Elf32_External_Lib)); + break; + case DT_MIPS_LIBLISTNO: + liblistno = entry->d_un.d_val; + break; + case DT_MIPS_OPTIONS: + options_offset = offset_from_vma (file, entry->d_un.d_val, 0); + break; + case DT_MIPS_CONFLICT: + conflicts_offset + = offset_from_vma (file, entry->d_un.d_val, + conflictsno * sizeof (Elf32_External_Conflict)); + 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 = 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); + snprintf (timebuf, sizeof (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 (VALID_DYNAMIC_NAME (liblist.l_name)) + print_symbol (20, GET_DYNAMIC_NAME (liblist.l_name)); + else + printf ("", 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 = get_data (NULL, file, options_offset, 1, sect->sh_size, + _("options")); + if (eopt) + { + iopt = cmalloc ((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_GET (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 = cmalloc (conflictsno, sizeof (*iconf)); + if (iconf == NULL) + { + error (_("Out of memory")); + return 0; + } + + if (is_32bit_elf) + { + Elf32_External_Conflict *econf32; + + econf32 = 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 = 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 %lu entries:\n"), + (unsigned 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 (' '); + if (VALID_DYNAMIC_NAME (psym->st_name)) + print_symbol (25, GET_DYNAMIC_NAME (psym->st_name)); + else + printf ("", psym->st_name); + putchar ('\n'); + } + + free (iconf); + } + + return 1; +} + +static int +process_gnu_liblist (FILE *file) +{ + Elf_Internal_Shdr *section, *string_sec; + Elf32_External_Lib *elib; + char *strtab; + size_t strtab_size; + 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: + if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum) + break; + + elib = get_data (NULL, file, section->sh_offset, 1, section->sh_size, + _("liblist")); + + if (elib == NULL) + break; + string_sec = SECTION_HEADER (section->sh_link); + + strtab = get_data (NULL, file, string_sec->sh_offset, 1, + string_sec->sh_size, _("liblist string table")); + strtab_size = string_sec->sh_size; + + 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); + snprintf (timebuf, sizeof (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", liblist.l_name < strtab_size + ? strtab + liblist.l_name : ""); + else + printf ("%-20.20s", liblist.l_name < strtab_size + ? 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 (unsigned e_type) +{ + static char buff[64]; + + if (elf_header.e_type == ET_CORE) + switch (e_type) + { + case NT_AUXV: + return _("NT_AUXV (auxiliary vector)"); + 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: + break; + } + else + switch (e_type) + { + case NT_VERSION: + return _("NT_VERSION (version)"); + case NT_ARCH: + return _("NT_ARCH (architecture)"); + default: + break; + } + + snprintf (buff, sizeof (buff), _("Unknown note type: (0x%08x)"), e_type); + return buff; +} + +static const char * +get_netbsd_elfcore_note_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) + { + snprintf (buff, sizeof (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; + } + } + + snprintf (buff, sizeof (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 (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 (strneq (pnote->namedata, "NetBSD-CORE", 11)) + /* 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 *file, bfd_vma offset, bfd_vma length) +{ + Elf_External_Note *pnotes; + Elf_External_Note *external; + int res = 1; + + if (length <= 0) + return 0; + + pnotes = get_data (NULL, file, offset, 1, 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 %lx into core notes\n"), + (long)((char *)external - (char *)pnotes)); + warn (_(" type: %lx, 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) +{ + Elf_Internal_Phdr *segment; + unsigned int i; + int res = 1; + + if (! get_program_headers (file)) + 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); + } + + return res; +} + +static int +process_note_sections (FILE *file) +{ + Elf_Internal_Shdr *section; + unsigned long i; + int res = 1; + + for (i = 0, section = section_headers; + i < elf_header.e_shnum; + i++, section++) + if (section->sh_type == SHT_NOTE) + res &= process_corefile_note_segment (file, + (bfd_vma) section->sh_offset, + (bfd_vma) section->sh_size); + + return res; +} + +static int +process_notes (FILE *file) +{ + /* If we have not been asked to display the notes then do nothing. */ + if (! do_notes) + return 1; + + if (elf_header.e_type != ET_CORE) + return process_note_sections (file); + + /* No program headers means no NOTE segment. */ + if (elf_header.e_phnum > 0) + return process_corefile_note_segments (file); + + printf (_("No note segments present in the core file.\n")); + return 1; +} + +static int +process_arch_specific (FILE *file) +{ + if (! do_arch) + return 1; + + switch (elf_header.e_machine) + { + case EM_ARM: + return process_arm_specific (file); + 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) +{ + /* 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 + overwriting 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_GET (ehdr64.e_entry); + elf_header.e_phoff = BYTE_GET (ehdr64.e_phoff); + elf_header.e_shoff = BYTE_GET (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); + } + + is_relocatable = elf_header.e_type == ET_REL; + + return 1; +} + +/* Process one ELF object file according to the command line options. + This file may actually be stored in an archive. The file is + positioned at the start of the ELF object. */ + +static int +process_object (char *file_name, FILE *file) +{ + unsigned int i; + + if (! get_file_header (file)) + { + error (_("%s: Failed to read file header\n"), file_name); + 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); + + /* Initialise the dump_sects array from the cmdline_dump_sects array. + Note we do this even if cmdline_dump_sects is empty because we + must make sure that the dump_sets array is zeroed out before each + object file is processed. */ + if (num_dump_sects > num_cmdline_dump_sects) + memset (dump_sects, 0, num_dump_sects); + + if (num_cmdline_dump_sects > 0) + { + if (num_dump_sects == 0) + /* A sneaky way of allocating the dump_sects array. */ + request_dump (num_cmdline_dump_sects, 0); + + assert (num_dump_sects >= num_cmdline_dump_sects); + memcpy (dump_sects, cmdline_dump_sects, num_cmdline_dump_sects); + } + + if (! process_file_header ()) + 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_section_groups (file)) + { + /* Without loaded section groups we cannot process unwind. */ + do_unwind = 0; + } + + if (process_program_headers (file)) + process_dynamic_section (file); + + process_relocs (file); + + process_unwind (file); + + process_symbol_table (file); + + process_syminfo (file); + + process_version_sections (file); + + process_section_contents (file); + + process_notes (file); + + process_gnu_liblist (file); + + process_arch_specific (file); + + if (program_headers) + { + free (program_headers); + program_headers = NULL; + } + + 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; + dynamic_strings_length = 0; + } + + if (dynamic_symbols) + { + free (dynamic_symbols); + dynamic_symbols = NULL; + num_dynamic_syms = 0; + } + + if (dynamic_syminfo) + { + free (dynamic_syminfo); + dynamic_syminfo = NULL; + } + + if (section_headers_groups) + { + free (section_headers_groups); + section_headers_groups = NULL; + } + + if (section_groups) + { + struct group_list *g, *next; + + for (i = 0; i < group_count; i++) + { + for (g = section_groups [i].root; g != NULL; g = next) + { + next = g->next; + free (g); + } + } + + free (section_groups); + section_groups = NULL; + } + + free_debug_memory (); + + return 0; +} + +/* Process an ELF archive. The file is positioned just after the + ARMAG string. */ + +static int +process_archive (char *file_name, FILE *file) +{ + struct ar_hdr arhdr; + size_t got; + unsigned long size; + char *longnames = NULL; + unsigned long longnames_size = 0; + size_t file_name_size; + int ret; + + show_name = 1; + + got = fread (&arhdr, 1, sizeof arhdr, file); + if (got != sizeof arhdr) + { + if (got == 0) + return 0; + + error (_("%s: failed to read archive header\n"), file_name); + return 1; + } + + if (memcmp (arhdr.ar_name, "/ ", 16) == 0) + { + /* This is the archive symbol table. Skip it. + FIXME: We should have an option to dump it. */ + size = strtoul (arhdr.ar_size, NULL, 10); + if (fseek (file, size + (size & 1), SEEK_CUR) != 0) + { + error (_("%s: failed to skip archive symbol table\n"), file_name); + return 1; + } + + got = fread (&arhdr, 1, sizeof arhdr, file); + if (got != sizeof arhdr) + { + if (got == 0) + return 0; + + error (_("%s: failed to read archive header\n"), file_name); + return 1; + } + } + + if (memcmp (arhdr.ar_name, "// ", 16) == 0) + { + /* This is the archive string table holding long member + names. */ + + longnames_size = strtoul (arhdr.ar_size, NULL, 10); + + longnames = malloc (longnames_size); + if (longnames == NULL) + { + error (_("Out of memory\n")); + return 1; + } + + if (fread (longnames, longnames_size, 1, file) != 1) + { + free (longnames); + error (_("%s: failed to read string table\n"), file_name); + return 1; + } + + if ((longnames_size & 1) != 0) + getc (file); + + got = fread (&arhdr, 1, sizeof arhdr, file); + if (got != sizeof arhdr) + { + free (longnames); + + if (got == 0) + return 0; + + error (_("%s: failed to read archive header\n"), file_name); + return 1; + } + } + + file_name_size = strlen (file_name); + ret = 0; + + while (1) + { + char *name; + char *nameend; + char *namealc; + + if (arhdr.ar_name[0] == '/') + { + unsigned long off; + + off = strtoul (arhdr.ar_name + 1, NULL, 10); + if (off >= longnames_size) + { + error (_("%s: invalid archive string table offset %lu\n"), file_name, off); + ret = 1; + break; + } + + name = longnames + off; + nameend = memchr (name, '/', longnames_size - off); + } + else + { + name = arhdr.ar_name; + nameend = memchr (name, '/', 16); + } + + if (nameend == NULL) + { + error (_("%s: bad archive file name\n"), file_name); + ret = 1; + break; + } + + namealc = malloc (file_name_size + (nameend - name) + 3); + if (namealc == NULL) + { + error (_("Out of memory\n")); + ret = 1; + break; + } + + memcpy (namealc, file_name, file_name_size); + namealc[file_name_size] = '('; + memcpy (namealc + file_name_size + 1, name, nameend - name); + namealc[file_name_size + 1 + (nameend - name)] = ')'; + namealc[file_name_size + 2 + (nameend - name)] = '\0'; + + archive_file_offset = ftell (file); + archive_file_size = strtoul (arhdr.ar_size, NULL, 10); + + ret |= process_object (namealc, file); + + free (namealc); + + if (fseek (file, + (archive_file_offset + + archive_file_size + + (archive_file_size & 1)), + SEEK_SET) != 0) + { + error (_("%s: failed to seek to next archive header\n"), file_name); + ret = 1; + break; + } + + got = fread (&arhdr, 1, sizeof arhdr, file); + if (got != sizeof arhdr) + { + if (got == 0) + break; + + error (_("%s: failed to read archive header\n"), file_name); + ret = 1; + break; + } + } + + if (longnames != 0) + free (longnames); + + return ret; +} + +static int +process_file (char *file_name) +{ + FILE *file; + struct stat statbuf; + char armag[SARMAG]; + int ret; + + if (stat (file_name, &statbuf) < 0) + { + if (errno == ENOENT) + error (_("'%s': No such file\n"), file_name); + else + error (_("Could not locate '%s'. System error message: %s\n"), + file_name, strerror (errno)); + return 1; + } + + if (! S_ISREG (statbuf.st_mode)) + { + error (_("'%s' is not an ordinary file\n"), file_name); + return 1; + } + + file = fopen (file_name, "rb"); + if (file == NULL) + { + error (_("Input file '%s' is not readable.\n"), file_name); + return 1; + } + + if (fread (armag, SARMAG, 1, file) != 1) + { + error (_("%s: Failed to read file header\n"), file_name); + fclose (file); + return 1; + } + + if (memcmp (armag, ARMAG, SARMAG) == 0) + ret = process_archive (file_name, file); + else + { + rewind (file); + archive_file_size = archive_file_offset = 0; + ret = process_object (file_name, file); + } + + fclose (file); + + return ret; +} + +#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 (int argc, char **argv) +{ + int err; + +#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); + + expandargv (&argc, &argv); + + parse_args (argc, argv); + + if (num_dump_sects > 0) + { + /* Make a copy of the dump_sects array. */ + 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; + } + } + + if (optind < (argc - 1)) + show_name = 1; + + err = 0; + while (optind < argc) + err |= process_file (argv[optind++]); + + if (dump_sects != NULL) + free (dump_sects); + if (cmdline_dump_sects != NULL) + free (cmdline_dump_sects); + + return err; +} diff --git a/contrib/binutils-2.17/binutils/rename.c b/contrib/binutils-2.17/binutils/rename.c new file mode 100644 index 0000000000..7d21cb34c0 --- /dev/null +++ b/contrib/binutils-2.17/binutils/rename.c @@ -0,0 +1,219 @@ +/* rename.c -- rename a file, preserving symlinks. + Copyright 1999, 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 + +#if ! defined (_WIN32) || defined (__CYGWIN32__) +static int simple_copy (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 (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; +} +#endif /* __CYGWIN32__ or not _WIN32 */ + +/* Set the times of the file DESTINATION to be the same as those in + STATBUF. */ + +void +set_times (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 (const char *from, const char *to, int preserve_dates ATTRIBUTE_UNUSED) +{ + 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 (_("unable to rename '%s' reason: %s"), to, strerror (errno)); + unlink (from); + } +#else + /* Use rename only if TO is not a symbolic link and has + only one hard link, and we have permission to write to it. */ + if (! exists + || (!S_ISLNK (s.st_mode) + && S_ISREG (s.st_mode) + && (s.st_mode & S_IWUSR) + && 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 (_("unable to rename '%s' reason: %s"), to, strerror (errno)); + unlink (from); + } + } + else + { + ret = simple_copy (from, to); + if (ret != 0) + non_fatal (_("unable to copy file '%s' reason: %s"), to, strerror (errno)); + + if (preserve_dates) + set_times (to, &s); + unlink (from); + } +#endif /* _WIN32 && !__CYGWIN32__ */ + + return ret; +} diff --git a/contrib/binutils-2.17/binutils/size.c b/contrib/binutils-2.17/binutils/size.c new file mode 100644 index 0000000000..b78cba02ba --- /dev/null +++ b/contrib/binutils-2.17/binutils/size.c @@ -0,0 +1,552 @@ +/* size.c -- report size of various sections of an executable file. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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; + +/* 0 means use AT&T-style output. */ +static int berkeley_format = BSD_DEFAULT; + +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 (FILE *, int); +static void display_file (char *); +static void display_bfd (bfd *); +static void display_archive (bfd *); +static int size_number (bfd_size_type); +static void rprint_number (int, bfd_size_type); +static void print_berkeley_format (bfd *); +static void sysv_internal_sizer (bfd *, asection *, void *); +static void sysv_internal_printer (bfd *, asection *, void *); +static void print_sysv_format (bfd *); +static void print_sizes (bfd * file); +static void berkeley_sum (bfd *, sec_ptr, void *); + +static void +usage (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\ + @ Read options from \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); +} + +static 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 (int, char **); + +int +main (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); + + expandargv (&argc, &argv); + + 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 (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 (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 (char *filename) +{ + bfd *file; + + if (get_file_size (filename) < 1) + return; + + 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 (bfd_size_type num) +{ + char buffer[40]; + + sprintf (buffer, + (radix == decimal ? "%lu" : + ((radix == octal) ? "0%lo" : "0x%lx")), + (unsigned long) num); + + return strlen (buffer); +} + +static void +rprint_number (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 (bfd *abfd ATTRIBUTE_UNUSED, sec_ptr sec, + void *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 (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 (bfd *abfd) +{ + static int files_seen = 0; + bfd_size_type total; + + bsssize = 0; + datasize = 0; + textsize = 0; + + bfd_map_over_sections (abfd, berkeley_sum, NULL); + + if (files_seen++ == 0) + puts ((radix == octal) ? " text\t data\t bss\t oct\t hex\tfilename" : + " text\t data\t bss\t dec\t hex\tfilename"); + + 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 (bfd *file ATTRIBUTE_UNUSED, sec_ptr sec, + void *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 (bfd *file ATTRIBUTE_UNUSED, sec_ptr sec, + void *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 (bfd *file) +{ + /* Size all of the columns. */ + svi_total = 0; + svi_maxvma = 0; + svi_namelen = 0; + bfd_map_over_sections (file, sysv_internal_sizer, 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, NULL); + + printf ("%-*s ", svi_namelen, "Total"); + rprint_number (svi_sizelen, svi_total); + printf ("\n\n"); +} + +static void +print_sizes (bfd *file) +{ + if (berkeley_format) + print_berkeley_format (file); + else + print_sysv_format (file); +} diff --git a/contrib/binutils-2.17/binutils/stabs.c b/contrib/binutils-2.17/binutils/stabs.c new file mode 100644 index 0000000000..879a3e2c7a --- /dev/null +++ b/contrib/binutils-2.17/binutils/stabs.c @@ -0,0 +1,5399 @@ +/* stabs.c -- Parse stabs debugging information + Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 + 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 (const char *, int); +static bfd_vma parse_number (const char **, bfd_boolean *); +static void bad_stab (const char *); +static void warn_stab (const char *, const char *); +static bfd_boolean parse_stab_string + (void *, struct stab_handle *, int, int, bfd_vma, const char *); +static debug_type parse_stab_type + (void *, struct stab_handle *, const char *, const char **, debug_type **); +static bfd_boolean parse_stab_type_number (const char **, int *); +static debug_type parse_stab_range_type + (void *, struct stab_handle *, const char *, const char **, const int *); +static debug_type parse_stab_sun_builtin_type (void *, const char **); +static debug_type parse_stab_sun_floating_type (void *, const char **); +static debug_type parse_stab_enum_type (void *, const char **); +static debug_type parse_stab_struct_type + (void *, struct stab_handle *, const char *, const char **, + bfd_boolean, const int *); +static bfd_boolean parse_stab_baseclasses + (void *, struct stab_handle *, const char **, debug_baseclass **); +static bfd_boolean parse_stab_struct_fields + (void *, struct stab_handle *, const char **, debug_field **, bfd_boolean *); +static bfd_boolean parse_stab_cpp_abbrev + (void *, struct stab_handle *, const char **, debug_field *); +static bfd_boolean parse_stab_one_struct_field + (void *, struct stab_handle *, const char **, const char *, + debug_field *, bfd_boolean *); +static bfd_boolean parse_stab_members + (void *, struct stab_handle *, const char *, const char **, const int *, + debug_method **); +static debug_type parse_stab_argtypes + (void *, 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 + (void *, struct stab_handle *, const char **, const int *, debug_type *, + bfd_boolean *); +static debug_type parse_stab_array_type + (void *, struct stab_handle *, const char **, bfd_boolean); +static void push_bincl (struct stab_handle *, const char *, bfd_vma); +static const char *pop_bincl (struct stab_handle *); +static bfd_boolean find_excl (struct stab_handle *, const char *, bfd_vma); +static bfd_boolean stab_record_variable + (void *, struct stab_handle *, const char *, debug_type, + enum debug_var_kind, bfd_vma); +static bfd_boolean stab_emit_pending_vars (void *, struct stab_handle *); +static debug_type *stab_find_slot (struct stab_handle *, const int *); +static debug_type stab_find_type (void *, struct stab_handle *, const int *); +static bfd_boolean stab_record_type + (void *, struct stab_handle *, const int *, debug_type); +static debug_type stab_xcoff_builtin_type + (void *, struct stab_handle *, int); +static debug_type stab_find_tagged_type + (void *, struct stab_handle *, const char *, int, enum debug_type_kind); +static debug_type *stab_demangle_argtypes + (void *, struct stab_handle *, const char *, bfd_boolean *, unsigned int); +static debug_type *stab_demangle_v3_argtypes + (void *, struct stab_handle *, const char *, bfd_boolean *); +static debug_type *stab_demangle_v3_arglist + (void *, struct stab_handle *, struct demangle_component *, bfd_boolean *); +static debug_type stab_demangle_v3_arg + (void *, struct stab_handle *, struct demangle_component *, debug_type, + bfd_boolean *); + +/* Save a string in memory. */ + +static char * +savestring (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 (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 (const char *p) +{ + fprintf (stderr, _("Bad stab: %s\n"), p); +} + +/* Warn about something in a stab string. */ + +static void +warn_stab (const char *p, const char *err) +{ + fprintf (stderr, _("Warning: %s: %s\n"), err, p); +} + +/* Create a handle to parse stabs symbols with. */ + +void * +start_stab (void *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 (void *) 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 (void *dhandle, void *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 (void *dhandle, void *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 (void *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 (void *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 (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 (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 (void *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 (void *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 (void *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 (void *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 (names, alloc * sizeof *names)); + values = ((bfd_signed_vma *) + xrealloc (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 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 (void *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 (void *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 (void *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 (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 (void *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 (void *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 (void *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 weird 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 (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 (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 (void *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; + bfd_boolean is_v3; + 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); + is_v3 = argtypes[0] == '_' && argtypes[1] == 'Z'; + + if (is_destructor || is_full_physname_constructor || is_v3) + *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 (void *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 (void *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 (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 (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 (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 (struct stab_handle *info, const char *name, bfd_vma hash) +{ + struct bincl_file *l; + + ++info->files; + info->file_types = ((struct stab_types **) + xrealloc (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 (void *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 (void *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 (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 (void *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 (void *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 (void *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 (void *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. */ + void *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 (const char *); +static unsigned int stab_demangle_count (const char **); +static bfd_boolean stab_demangle_get_count (const char **, unsigned int *); +static bfd_boolean stab_demangle_prefix + (struct stab_demangle_info *, const char **, unsigned int); +static bfd_boolean stab_demangle_function_name + (struct stab_demangle_info *, const char **, const char *); +static bfd_boolean stab_demangle_signature + (struct stab_demangle_info *, const char **); +static bfd_boolean stab_demangle_qualified + (struct stab_demangle_info *, const char **, debug_type *); +static bfd_boolean stab_demangle_template + (struct stab_demangle_info *, const char **, char **); +static bfd_boolean stab_demangle_class + (struct stab_demangle_info *, const char **, const char **); +static bfd_boolean stab_demangle_args + (struct stab_demangle_info *, const char **, debug_type **, bfd_boolean *); +static bfd_boolean stab_demangle_arg + (struct stab_demangle_info *, const char **, debug_type **, + unsigned int *, unsigned int *); +static bfd_boolean stab_demangle_type + (struct stab_demangle_info *, const char **, debug_type *); +static bfd_boolean stab_demangle_fund_type + (struct stab_demangle_info *, const char **, debug_type *); +static bfd_boolean stab_demangle_remember_type + (struct stab_demangle_info *, const char *, int); + +/* Warn about a bad demangling. */ + +static void +stab_bad_demangle (const char *s) +{ + fprintf (stderr, _("bad mangled name `%s'\n"), s); +} + +/* Get a count from a stab string. */ + +static unsigned int +stab_demangle_count (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 (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 (void *dhandle, struct stab_handle *info, + const char *physname, bfd_boolean *pvarargs, + unsigned int physname_len) +{ + struct stab_demangle_info minfo; + + /* Check for the g++ V3 ABI. */ + if (physname[0] == '_' && physname[1] == 'Z') + return stab_demangle_v3_argtypes (dhandle, info, physname, pvarargs); + + 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 (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 (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 (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 (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 (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; + + len = stab_demangle_count (pp); + if (len == 0) + { + 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 (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 (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 (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 (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 (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 (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; +} + +/* Demangle names encoded using the g++ V3 ABI. The newer versions of + g++ which use this ABI do not encode ordinary method argument types + in a mangled name; they simply output the argument types. However, + for a static method, g++ simply outputs the return type and the + physical name. So in that case we need to demangle the name here. + Here PHYSNAME is the physical name of the function, and we set the + variable pointed at by PVARARGS to indicate whether this function + is varargs. This returns NULL, or a NULL terminated array of + argument types. */ + +static debug_type * +stab_demangle_v3_argtypes (void *dhandle, struct stab_handle *info, + const char *physname, bfd_boolean *pvarargs) +{ + struct demangle_component *dc; + void *mem; + debug_type *pargs; + + dc = cplus_demangle_v3_components (physname, DMGL_PARAMS | DMGL_ANSI, &mem); + if (dc == NULL) + { + stab_bad_demangle (physname); + return NULL; + } + + /* We expect to see TYPED_NAME, and the right subtree describes the + function type. */ + if (dc->type != DEMANGLE_COMPONENT_TYPED_NAME + || dc->u.s_binary.right->type != DEMANGLE_COMPONENT_FUNCTION_TYPE) + { + fprintf (stderr, _("Demangled name is not a function\n")); + free (mem); + return NULL; + } + + pargs = stab_demangle_v3_arglist (dhandle, info, + dc->u.s_binary.right->u.s_binary.right, + pvarargs); + + free (mem); + + return pargs; +} + +/* Demangle an argument list in a struct demangle_component tree. + Returns a DEBUG_TYPE_NULL terminated array of argument types, and + sets *PVARARGS to indicate whether this is a varargs function. */ + +static debug_type * +stab_demangle_v3_arglist (void *dhandle, struct stab_handle *info, + struct demangle_component *arglist, + bfd_boolean *pvarargs) +{ + struct demangle_component *dc; + unsigned int alloc, count; + debug_type *pargs; + + alloc = 10; + pargs = (debug_type *) xmalloc (alloc * sizeof *pargs); + *pvarargs = FALSE; + + count = 0; + + for (dc = arglist; + dc != NULL; + dc = dc->u.s_binary.right) + { + debug_type arg; + bfd_boolean varargs; + + if (dc->type != DEMANGLE_COMPONENT_ARGLIST) + { + fprintf (stderr, _("Unexpected type in v3 arglist demangling\n")); + free (pargs); + return NULL; + } + + arg = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left, + NULL, &varargs); + if (arg == NULL) + { + if (varargs) + { + *pvarargs = TRUE; + continue; + } + free (pargs); + return NULL; + } + + if (count + 1 >= alloc) + { + alloc += 10; + pargs = (debug_type *) xrealloc (pargs, alloc * sizeof *pargs); + } + + pargs[count] = arg; + ++count; + } + + pargs[count] = DEBUG_TYPE_NULL; + + return pargs; +} + +/* Convert a struct demangle_component tree describing an argument + type into a debug_type. */ + +static debug_type +stab_demangle_v3_arg (void *dhandle, struct stab_handle *info, + struct demangle_component *dc, debug_type context, + bfd_boolean *pvarargs) +{ + debug_type dt; + + if (pvarargs != NULL) + *pvarargs = FALSE; + + switch (dc->type) + { + /* FIXME: These are demangle component types which we probably + need to handle one way or another. */ + case DEMANGLE_COMPONENT_LOCAL_NAME: + case DEMANGLE_COMPONENT_TYPED_NAME: + case DEMANGLE_COMPONENT_TEMPLATE_PARAM: + case DEMANGLE_COMPONENT_CTOR: + case DEMANGLE_COMPONENT_DTOR: + case DEMANGLE_COMPONENT_JAVA_CLASS: + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + case DEMANGLE_COMPONENT_COMPLEX: + case DEMANGLE_COMPONENT_IMAGINARY: + case DEMANGLE_COMPONENT_VENDOR_TYPE: + case DEMANGLE_COMPONENT_ARRAY_TYPE: + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + case DEMANGLE_COMPONENT_ARGLIST: + default: + fprintf (stderr, _("Unrecognized demangle component %d\n"), + (int) dc->type); + return NULL; + + case DEMANGLE_COMPONENT_NAME: + if (context != NULL) + { + const debug_field *fields; + + fields = debug_get_fields (dhandle, context); + if (fields != NULL) + { + /* Try to find this type by looking through the context + class. */ + for (; *fields != DEBUG_FIELD_NULL; fields++) + { + debug_type ft; + const char *dn; + + ft = debug_get_field_type (dhandle, *fields); + if (ft == NULL) + return NULL; + dn = debug_get_type_name (dhandle, ft); + if (dn != NULL + && (int) strlen (dn) == dc->u.s_name.len + && strncmp (dn, dc->u.s_name.s, dc->u.s_name.len) == 0) + return ft; + } + } + } + return stab_find_tagged_type (dhandle, info, dc->u.s_name.s, + dc->u.s_name.len, DEBUG_KIND_ILLEGAL); + + case DEMANGLE_COMPONENT_QUAL_NAME: + context = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left, + context, NULL); + if (context == NULL) + return NULL; + return stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.right, + context, NULL); + + case DEMANGLE_COMPONENT_TEMPLATE: + { + char *p; + size_t alc; + + /* We print this component to get a class name which we can + use. FIXME: This probably won't work if the template uses + template parameters which refer to an outer template. */ + p = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, dc, 20, &alc); + if (p == NULL) + { + fprintf (stderr, _("Failed to print demangled template\n")); + return NULL; + } + dt = stab_find_tagged_type (dhandle, info, p, strlen (p), + DEBUG_KIND_CLASS); + free (p); + return dt; + } + + case DEMANGLE_COMPONENT_SUB_STD: + return stab_find_tagged_type (dhandle, info, dc->u.s_string.string, + dc->u.s_string.len, DEBUG_KIND_ILLEGAL); + + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_CONST: + case DEMANGLE_COMPONENT_POINTER: + case DEMANGLE_COMPONENT_REFERENCE: + dt = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left, NULL, + NULL); + if (dt == NULL) + return NULL; + + switch (dc->type) + { + default: + abort (); + case DEMANGLE_COMPONENT_RESTRICT: + /* FIXME: We have no way to represent restrict. */ + return dt; + case DEMANGLE_COMPONENT_VOLATILE: + return debug_make_volatile_type (dhandle, dt); + case DEMANGLE_COMPONENT_CONST: + return debug_make_const_type (dhandle, dt); + case DEMANGLE_COMPONENT_POINTER: + return debug_make_pointer_type (dhandle, dt); + case DEMANGLE_COMPONENT_REFERENCE: + return debug_make_reference_type (dhandle, dt); + } + + case DEMANGLE_COMPONENT_FUNCTION_TYPE: + { + debug_type *pargs; + bfd_boolean varargs; + + if (dc->u.s_binary.left == NULL) + { + /* In this case the return type is actually unknown. + However, I'm not sure this will ever arise in practice; + normally an unknown return type would only appear at + the top level, which is handled above. */ + dt = debug_make_void_type (dhandle); + } + else + dt = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left, NULL, + NULL); + if (dt == NULL) + return NULL; + + pargs = stab_demangle_v3_arglist (dhandle, info, + dc->u.s_binary.right, + &varargs); + if (pargs == NULL) + return NULL; + + return debug_make_function_type (dhandle, dt, pargs, varargs); + } + + case DEMANGLE_COMPONENT_BUILTIN_TYPE: + { + char *p; + size_t alc; + debug_type ret; + + /* We print this component in order to find out the type name. + FIXME: Should we instead expose the + demangle_builtin_type_info structure? */ + p = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, dc, 20, &alc); + if (p == NULL) + { + fprintf (stderr, _("Couldn't get demangled builtin type\n")); + return NULL; + } + + /* The mangling is based on the type, but does not itself + indicate what the sizes are. So we have to guess. */ + if (strcmp (p, "signed char") == 0) + ret = debug_make_int_type (dhandle, 1, FALSE); + else if (strcmp (p, "bool") == 0) + ret = debug_make_bool_type (dhandle, 1); + else if (strcmp (p, "char") == 0) + ret = debug_make_int_type (dhandle, 1, FALSE); + else if (strcmp (p, "double") == 0) + ret = debug_make_float_type (dhandle, 8); + else if (strcmp (p, "long double") == 0) + ret = debug_make_float_type (dhandle, 8); + else if (strcmp (p, "float") == 0) + ret = debug_make_float_type (dhandle, 4); + else if (strcmp (p, "__float128") == 0) + ret = debug_make_float_type (dhandle, 16); + else if (strcmp (p, "unsigned char") == 0) + ret = debug_make_int_type (dhandle, 1, TRUE); + else if (strcmp (p, "int") == 0) + ret = debug_make_int_type (dhandle, 4, FALSE); + else if (strcmp (p, "unsigned int") == 0) + ret = debug_make_int_type (dhandle, 4, TRUE); + else if (strcmp (p, "long") == 0) + ret = debug_make_int_type (dhandle, 4, FALSE); + else if (strcmp (p, "unsigned long") == 0) + ret = debug_make_int_type (dhandle, 4, TRUE); + else if (strcmp (p, "__int128") == 0) + ret = debug_make_int_type (dhandle, 16, FALSE); + else if (strcmp (p, "unsigned __int128") == 0) + ret = debug_make_int_type (dhandle, 16, TRUE); + else if (strcmp (p, "short") == 0) + ret = debug_make_int_type (dhandle, 2, FALSE); + else if (strcmp (p, "unsigned short") == 0) + ret = debug_make_int_type (dhandle, 2, TRUE); + else if (strcmp (p, "void") == 0) + ret = debug_make_void_type (dhandle); + else if (strcmp (p, "wchar_t") == 0) + ret = debug_make_int_type (dhandle, 4, TRUE); + else if (strcmp (p, "long long") == 0) + ret = debug_make_int_type (dhandle, 8, FALSE); + else if (strcmp (p, "unsigned long long") == 0) + ret = debug_make_int_type (dhandle, 8, TRUE); + else if (strcmp (p, "...") == 0) + { + if (pvarargs == NULL) + fprintf (stderr, _("Unexpected demangled varargs\n")); + else + *pvarargs = TRUE; + ret = NULL; + } + else + { + fprintf (stderr, _("Unrecognized demangled builtin type\n")); + ret = NULL; + } + + free (p); + + return ret; + } + } +} diff --git a/contrib/binutils-2.17/binutils/strings.c b/contrib/binutils-2.17/binutils/strings.c new file mode 100644 index 0000000000..a04cb581ea --- /dev/null +++ b/contrib/binutils-2.17/binutils/strings.c @@ -0,0 +1,727 @@ +/* strings -- print the strings of printable characters in files + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2005 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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" +#include + +/* 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 +#ifdef HAVE_STAT64 +typedef struct stat64 statbuf; +#define file_stat(f,s) stat64(f, s) +#else +typedef struct stat statbuf; +#define file_stat(f,s) stat(f, s) +#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} +}; + +/* Records the size of a named file so that we + do not repeatedly run bfd_stat() on it. */ + +typedef struct +{ + const char * filename; + bfd_size_type filesize; +} filename_and_size_t; + +static void strings_a_section (bfd *, asection *, void *); +static bfd_boolean strings_object_file (const char *); +static bfd_boolean strings_file (char *file); +static int integer_arg (char *s); +static void print_strings (const char *, FILE *, file_off, int, int, char *); +static void usage (FILE *, int); +static long get_char (FILE *, file_off *, int *, char **); + +int main (int, char **); + +int +main (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); + + expandargv (&argc, &argv); + + 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 in + ARG->filename and whose size might be in ARG->filesize. If it + contains initialized data set `got_a_section' and print the + strings in it. + + FIXME: We ought to be able to return error codes/messages for + certain conditions. */ + +static void +strings_a_section (bfd *abfd, asection *sect, void *arg) +{ + filename_and_size_t * filename_and_sizep; + bfd_size_type *filesizep; + bfd_size_type sectsize; + void *mem; + + if ((sect->flags & DATA_FLAGS) != DATA_FLAGS) + return; + + sectsize = bfd_get_section_size (sect); + + if (sectsize <= 0) + return; + + /* Get the size of the file. This might have been cached for us. */ + filename_and_sizep = (filename_and_size_t *) arg; + filesizep = & filename_and_sizep->filesize; + + if (*filesizep == 0) + { + struct stat st; + + if (bfd_stat (abfd, &st)) + return; + + /* Cache the result so that we do not repeatedly stat this file. */ + *filesizep = st.st_size; + } + + /* Compare the size of the section against the size of the file. + If the section is bigger then the file must be corrupt and + we should not try dumping it. */ + if (sectsize >= *filesizep) + return; + + mem = xmalloc (sectsize); + + if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sectsize)) + { + got_a_section = TRUE; + + print_strings (filename_and_sizep->filename, NULL, sect->filepos, + 0, sectsize, 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 (const char *file) +{ + filename_and_size_t filename_and_size; + bfd *abfd; + + 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; + filename_and_size.filename = file; + filename_and_size.filesize = 0; + bfd_map_over_sections (abfd, strings_a_section, & filename_and_size); + + 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 (char *file) +{ + statbuf st; + + if (file_stat (file, &st) < 0) + { + if (errno == ENOENT) + non_fatal (_("'%s': No such file"), file); + else + non_fatal (_("Warning: could not locate '%s'. reason: %s"), + file, strerror (errno)); + return FALSE; + } + + /* 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 (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; + + /* Only use getc_unlocked if we found a declaration for it. + Otherwise, libc is not thread safe by default, and we + should not use it. */ + +#if defined(HAVE_GETC_UNLOCKED) && HAVE_DECL_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 (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 ", (unsigned long) (start >> 32), + (unsigned long) (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 (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 (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,d,x} 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\ + @ Read options from \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.17/binutils/unwind-ia64.c b/contrib/binutils-2.17/binutils/unwind-ia64.c new file mode 100644 index 0000000000..c104e72bbc --- /dev/null +++ b/contrib/binutils-2.17/binutils/unwind-ia64.c @@ -0,0 +1,1082 @@ +/* unwind-ia64.c -- utility routines to dump IA-64 unwind info for readelf. + Copyright 2000, 2001, 2002, 2003 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, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 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" + +static bfd_vma unw_rlen = 0; + +static void unw_print_brmask (char *, unsigned int); +static void unw_print_grmask (char *, unsigned int); +static void unw_print_frmask (char *, unsigned int); +static void unw_print_abreg (char *, unsigned int); +static void unw_print_xyreg (char *, unsigned int, unsigned int); + +static void +unw_print_brmask (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 (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 (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 (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 (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[20]; \ + \ + 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[20]; \ + \ + 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[20]; \ + \ + 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[20], tregname[20]; \ + \ + 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 (const unsigned char **); +static const unsigned char *unw_decode_x1 + (const unsigned char *, unsigned int, void *); +static const unsigned char *unw_decode_x2 + (const unsigned char *, unsigned int, void *); +static const unsigned char *unw_decode_x3 + (const unsigned char *, unsigned int, void *); +static const unsigned char *unw_decode_x4 + (const unsigned char *, unsigned int, void *); +static const unsigned char *unw_decode_r1 + (const unsigned char *, unsigned int, void *); +static const unsigned char *unw_decode_r2 + (const unsigned char *, unsigned int, void *); +static const unsigned char *unw_decode_r3 + (const unsigned char *, unsigned int, void *); +static const unsigned char *unw_decode_p1 + (const unsigned char *, unsigned int, void *); +static const unsigned char *unw_decode_p2_p5 + (const unsigned char *, unsigned int, void *); +static const unsigned char *unw_decode_p6 + (const unsigned char *, unsigned int, void *); +static const unsigned char *unw_decode_p7_p10 + (const unsigned char *, unsigned int, void *); +static const unsigned char *unw_decode_b1 + (const unsigned char *, unsigned int, void *); +static const unsigned char *unw_decode_b2 + (const unsigned char *, unsigned int, void *); +static const unsigned char *unw_decode_b3_x4 + (const unsigned char *, unsigned int, void *); + +static unw_word +unw_decode_uleb128 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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) + (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 (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.17/binutils/unwind-ia64.h b/contrib/binutils-2.17/binutils/unwind-ia64.h new file mode 100644 index 0000000000..c2fb9b9394 --- /dev/null +++ b/contrib/binutils-2.17/binutils/unwind-ia64.h @@ -0,0 +1,31 @@ +/* unwind-ia64.h -- dump IA-64 unwind info. + Copyright 2000, 2001, 2002, 2003 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, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 (const unsigned char *, int, void *); diff --git a/contrib/binutils-2.17/binutils/version.c b/contrib/binutils-2.17/binutils/version.c new file mode 100644 index 0000000000..2843e69f06 --- /dev/null +++ b/contrib/binutils-2.17/binutils/version.c @@ -0,0 +1,40 @@ +/* version.c -- binutils version information + Copyright 1991, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + 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, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 (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 2005 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.17/binutils/wrstabs.c b/contrib/binutils-2.17/binutils/wrstabs.c new file mode 100644 index 0000000000..b75d6df584 --- /dev/null +++ b/contrib/binutils-2.17/binutils/wrstabs.c @@ -0,0 +1,2274 @@ +/* wrstabs.c -- Output stabs debugging information + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2006 + 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 + (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); +static bfd_boolean stab_write_symbol + (struct stab_write_handle *, int, int, bfd_vma, const char *); +static bfd_boolean stab_push_string + (struct stab_write_handle *, const char *, long, bfd_boolean, unsigned int); +static bfd_boolean stab_push_defined_type + (struct stab_write_handle *, long, unsigned int); +static char *stab_pop_type (struct stab_write_handle *); +static bfd_boolean stab_modify_type + (struct stab_write_handle *, int, unsigned int, long **, size_t *); +static long stab_get_struct_index + (struct stab_write_handle *, const char *, unsigned int, + enum debug_type_kind, unsigned int *); +static bfd_boolean stab_class_method_var + (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 (void *, const char *); +static bfd_boolean stab_start_source (void *, const char *); +static bfd_boolean stab_empty_type (void *); +static bfd_boolean stab_void_type (void *); +static bfd_boolean stab_int_type (void *, unsigned int, bfd_boolean); +static bfd_boolean stab_float_type (void *, unsigned int); +static bfd_boolean stab_complex_type (void *, unsigned int); +static bfd_boolean stab_bool_type (void *, unsigned int); +static bfd_boolean stab_enum_type + (void *, const char *, const char **, bfd_signed_vma *); +static bfd_boolean stab_pointer_type (void *); +static bfd_boolean stab_function_type (void *, int, bfd_boolean); +static bfd_boolean stab_reference_type (void *); +static bfd_boolean stab_range_type (void *, bfd_signed_vma, bfd_signed_vma); +static bfd_boolean stab_array_type + (void *, bfd_signed_vma, bfd_signed_vma, bfd_boolean); +static bfd_boolean stab_set_type (void *, bfd_boolean); +static bfd_boolean stab_offset_type (void *); +static bfd_boolean stab_method_type (void *, bfd_boolean, int, bfd_boolean); +static bfd_boolean stab_const_type (void *); +static bfd_boolean stab_volatile_type (void *); +static bfd_boolean stab_start_struct_type + (void *, const char *, unsigned int, bfd_boolean, unsigned int); +static bfd_boolean stab_struct_field + (void *, const char *, bfd_vma, bfd_vma, enum debug_visibility); +static bfd_boolean stab_end_struct_type (void *); +static bfd_boolean stab_start_class_type + (void *, const char *, unsigned int, bfd_boolean, unsigned int, + bfd_boolean, bfd_boolean); +static bfd_boolean stab_class_static_member + (void *, const char *, const char *, enum debug_visibility); +static bfd_boolean stab_class_baseclass + (void *, bfd_vma, bfd_boolean, enum debug_visibility); +static bfd_boolean stab_class_start_method (void *, const char *); +static bfd_boolean stab_class_method_variant + (void *, const char *, enum debug_visibility, bfd_boolean, bfd_boolean, + bfd_vma, bfd_boolean); +static bfd_boolean stab_class_static_method_variant + (void *, const char *, enum debug_visibility, bfd_boolean, bfd_boolean); +static bfd_boolean stab_class_end_method (void *); +static bfd_boolean stab_end_class_type (void *); +static bfd_boolean stab_typedef_type (void *, const char *); +static bfd_boolean stab_tag_type + (void *, const char *, unsigned int, enum debug_type_kind); +static bfd_boolean stab_typdef (void *, const char *); +static bfd_boolean stab_tag (void *, const char *); +static bfd_boolean stab_int_constant (void *, const char *, bfd_vma); +static bfd_boolean stab_float_constant (void *, const char *, double); +static bfd_boolean stab_typed_constant (void *, const char *, bfd_vma); +static bfd_boolean stab_variable + (void *, const char *, enum debug_var_kind, bfd_vma); +static bfd_boolean stab_start_function (void *, const char *, bfd_boolean); +static bfd_boolean stab_function_parameter + (void *, const char *, enum debug_parm_kind, bfd_vma); +static bfd_boolean stab_start_block (void *, bfd_vma); +static bfd_boolean stab_end_block (void *, bfd_vma); +static bfd_boolean stab_end_function (void *); +static bfd_boolean stab_lineno (void *, 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 (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 (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 (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 (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 (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 (bfd *abfd, void *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, + sizeof (struct string_hash_entry)) + || !bfd_hash_table_init (&info.typedef_hash.table, string_hash_newfunc, + sizeof (struct string_hash_entry))) + { + 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, (void *) &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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *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 (void *p ATTRIBUTE_UNUSED) +{ + return TRUE; +} + +/* Output a line number. */ + +static bfd_boolean +stab_lineno (void *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.17/gas/CONTRIBUTORS b/contrib/binutils-2.17/gas/CONTRIBUTORS new file mode 100644 index 0000000000..d564ba8f01 --- /dev/null +++ b/contrib/binutils-2.17/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.17/gas/COPYING b/contrib/binutils-2.17/gas/COPYING new file mode 100644 index 0000000000..22c7fc2011 --- /dev/null +++ b/contrib/binutils-2.17/gas/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright 1989, 1991, 1997 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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.17/gas/README b/contrib/binutils-2.17/gas/README new file mode 100644 index 0000000000..c249fd97fd --- /dev/null +++ b/contrib/binutils-2.17/gas/README @@ -0,0 +1,164 @@ + 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 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. + +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-binutils@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. + +See ../binutils/README for what we need in a bug report. diff --git a/contrib/binutils-2.17/gas/app.c b/contrib/binutils-2.17/gas/app.c new file mode 100644 index 0000000000..275ad68ebb --- /dev/null +++ b/contrib/binutils-2.17/gas/app.c @@ -0,0 +1,1409 @@ +/* This is the Assembler Pre-Processor + 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, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 (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 (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 (void) +{ + 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 (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 (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 (int (*get) (char *, int), char *tostart, int tolen) +{ + char *to = tostart; + char *toend = tostart + tolen; + char *from; + char *fromend; + int fromlen; + register int ch, ch2 = 0; + /* Character that started the string we're working on. */ + static char quotechar; + + /*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 +#ifdef TC_IA64 + 14: After seeing a `(' at state 0, looking for a `)' as + predicate. + 15: After seeing a `(' at state 1, looking for a `)' as + predicate. +#endif +#ifdef TC_Z80 + 16: After seeing an 'a' or an 'A' at the start of a symbol + 17: After seeing an 'f' or an 'F' in state 16 +#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; + if (ch == '\\' + || ch == quotechar + || 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; '%c' inserted"), quotechar); + state = old_state; + UNGET ('\n'); + PUT (quotechar); + } + else if (ch == quotechar) + { + 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; '%c' inserted"), quotechar); + PUT (quotechar); + 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 (); + quotechar = ch; + state = 5; + old_state = 8; + 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 +#ifdef TC_Z80 + case 16: + /* We have seen an 'a' at the start of a symbol, look for an 'f'. */ + ch = GET (); + if (ch == 'f' || ch == 'F') + { + state = 17; + PUT (ch); + } + else + { + state = 9; + break; + } + case 17: + /* We have seen "af" at the start of a symbol, + a ' here is a part of that symbol. */ + ch = GET (); + state = 9; + if (ch == '\'') + /* Change to avoid warning about unclosed string. */ + PUT ('`'); + else + UNGET (ch); + break; +#endif + } + + /* OK, we are somewhere in states 0 through 4 or 9 through 11. */ + + /* flushchar: */ + ch = GET (); + +#ifdef TC_IA64 + if (ch == '(' && (state == 0 || state == 1)) + { + state += 14; + PUT (ch); + continue; + } + else if (state == 14 || state == 15) + { + if (ch == ')') + { + state -= 14; + PUT (ch); + ch = GET (); + } + else + { + PUT (ch); + continue; + } + } +#endif + + 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: + quotechar = ch; + 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; + } + +#ifdef TC_Z80 + /* "af'" is a symbol containing '\''. */ + if (state == 3 && (ch == 'a' || ch == 'A')) + { + state = 16; + PUT (ch); + ch = GET (); + if (ch == 'f' || ch == 'F') + { + state = 17; + PUT (ch); + break; + } + else + { + state = 9; + if (!IS_SYMBOL_COMPONENT (ch)) + { + UNGET (ch); + break; + } + } + } +#endif + 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); + memcpy (to, from, len); + to += len; + from += len; + if (to >= toend) + goto tofull; + 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 (!IS_SYMBOL_COMPONENT (ch)) + 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.17/gas/as.c b/contrib/binutils-2.17/gas/as.c new file mode 100644 index 0000000000..727a1dd40e --- /dev/null +++ b/contrib/binutils-2.17/gas/as.c @@ -0,0 +1,1207 @@ +/* as.c - GAS main program. + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005 + 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, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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" +#include "dw2gencfi.h" +#include "hash.h" +#include "bfdver.h" + +#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 + +#ifdef USING_CGEN +/* Perform any cgen specific initialisation for gas. */ +extern void gas_cgen_begin (void); +#endif + +/* Keep a record of the itbl files we read in. */ +struct itbl_file_list +{ + struct itbl_file_list *next; + char *name; +}; + +/* 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; +}; + + +/* True if a listing is wanted. */ +int listing; + +/* Type of debugging to generate. */ +enum debug_info_type debug_type = DEBUG_UNSPECIFIED; +int use_gnu_debug_info_extensions = 0; + +#ifndef MD_DEBUG_FORMAT_SELECTOR +#define MD_DEBUG_FORMAT_SELECTOR NULL +#endif +static enum debug_info_type (*md_debug_format_selector) (int *) = MD_DEBUG_FORMAT_SELECTOR; + +/* Maximum level of macro nesting. */ +int max_macro_nest = 100; + +/* argv[0] */ +static char * myname; + +/* 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; + +/* Enable verbose mode. */ +int verbose = 0; + +segT reg_section; +segT expr_section; +segT text_section; +segT data_section; +segT bss_section; + +/* Name of listing file. */ +static char *listing_filename = NULL; + +static struct defsym_list *defsyms; + +static struct itbl_file_list *itbl_files; + +static long start_time; + +static int flag_macro_alternate; + + +#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 (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 (void) +{ + abort (); + return NULL; +} + +void +common_emul_init (void) +{ + 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 (void) +{ + static int printed; + + if (printed) + return; + printed = 1; + + fprintf (stderr, _("GNU assembler version %s (%s) using BFD version %s\n"), + VERSION, TARGET_ALIAS, BFD_VERSION_STRING); +} + +static void +show_usage (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, _("\ + --alternate initially turn on alternate macro syntax\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 +#if defined OBJ_ELF || defined OBJ_MAYBE_ELF + fprintf (stream, _("\ + --execstack require executable stack for this object\n")); + fprintf (stream, _("\ + --noexecstack don't require executable stack for this object\n")); +#endif + fprintf (stream, _("\ + -f skip whitespace and comment preprocessing\n")); + fprintf (stream, _("\ + -g --gen-debug generate debugging information\n")); + fprintf (stream, _("\ + --gstabs generate STABS debugging information\n")); + fprintf (stream, _("\ + --gstabs+ generate STABS debug info with GNU extensions\n")); + fprintf (stream, _("\ + --gdwarf-2 generate DWARF2 debugging information\n")); + fprintf (stream, _("\ + --hash-size= set the hash table size close to \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, _("\ + --reduce-memory-overheads \n\ + prefer smaller memory use at the cost of longer\n\ + assembly times\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")); + fprintf (stream, _("\ + @FILE read options from FILE\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 (int * pargc, char *** pargv) +{ + int old_argc; + int new_argc; + char ** old_argv; + char ** 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', 'a', ':', ':', 'D', 'f', 'g', ':',':', '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; + /* Codes used for the long options with no short synonyms. */ + enum option_values + { + OPTION_HELP = OPTION_STD_BASE, + OPTION_NOCPP, + OPTION_STATISTICS, + OPTION_VERSION, + OPTION_DUMPCONFIG, + OPTION_VERBOSE, + OPTION_EMULATION, + OPTION_DEFSYM, + OPTION_INSTTBL, + OPTION_LISTING_LHS_WIDTH, + OPTION_LISTING_LHS_WIDTH2, + OPTION_LISTING_RHS_WIDTH, + OPTION_LISTING_CONT_LINES, + OPTION_DEPFILE, + OPTION_GSTABS, + OPTION_GSTABS_PLUS, + OPTION_GDWARF2, + OPTION_STRIP_LOCAL_ABSOLUTE, + OPTION_TRADITIONAL_FORMAT, + OPTION_WARN, + OPTION_TARGET_HELP, + OPTION_EXECSTACK, + OPTION_NOEXECSTACK, + OPTION_ALTERNATE, + OPTION_AL, + OPTION_HASH_TABLE_SIZE, + OPTION_REDUCE_MEMORY_OVERHEADS, + OPTION_WARN_FATAL + /* When you add options here, check that they do + not collide with OPTION_MD_BASE. See as.h. */ + }; + + static const struct option std_longopts[] = + { + /* Note: commas are placed at the start of the line rather than + the end of the preceeding line so that it is simpler to + selectively add and remove lines from this list. */ + {"alternate", no_argument, NULL, OPTION_ALTERNATE} + /* The entry for "a" is here to prevent getopt_long_only() from + considering that -a is an abbreviation for --alternate. This is + necessary because -a= is a valid switch but getopt would + normally reject it since --alternate does not take an argument. */ + ,{"a", optional_argument, NULL, 'a'} + /* Handle -al=. */ + ,{"al", optional_argument, NULL, OPTION_AL} + ,{"defsym", required_argument, NULL, OPTION_DEFSYM} + ,{"dump-config", no_argument, NULL, OPTION_DUMPCONFIG} + ,{"emulation", required_argument, NULL, OPTION_EMULATION} +#if defined OBJ_ELF || defined OBJ_MAYBE_ELF + ,{"execstack", no_argument, NULL, OPTION_EXECSTACK} + ,{"noexecstack", no_argument, NULL, OPTION_NOEXECSTACK} +#endif + ,{"fatal-warnings", no_argument, NULL, OPTION_WARN_FATAL} + ,{"gdwarf-2", no_argument, NULL, OPTION_GDWARF2} + /* GCC uses --gdwarf-2 but GAS uses to use --gdwarf2, + so we keep it here for backwards compatibility. */ + ,{"gdwarf2", no_argument, NULL, OPTION_GDWARF2} + ,{"gen-debug", no_argument, NULL, 'g'} + ,{"gstabs", no_argument, NULL, OPTION_GSTABS} + ,{"gstabs+", no_argument, NULL, OPTION_GSTABS_PLUS} + ,{"hash-size", required_argument, NULL, OPTION_HASH_TABLE_SIZE} + ,{"help", no_argument, NULL, OPTION_HELP} + /* 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} + /* 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'} + ,{"listing-lhs-width", required_argument, NULL, OPTION_LISTING_LHS_WIDTH} + ,{"listing-lhs-width2", required_argument, NULL, OPTION_LISTING_LHS_WIDTH2} + ,{"listing-rhs-width", required_argument, NULL, OPTION_LISTING_RHS_WIDTH} + ,{"listing-cont-lines", required_argument, NULL, OPTION_LISTING_CONT_LINES} + ,{"MD", required_argument, NULL, OPTION_DEPFILE} + ,{"mri", no_argument, NULL, 'M'} + ,{"nocpp", no_argument, NULL, OPTION_NOCPP} + ,{"no-warn", no_argument, NULL, 'W'} + ,{"reduce-memory-overheads", no_argument, NULL, OPTION_REDUCE_MEMORY_OVERHEADS} + ,{"statistics", no_argument, NULL, OPTION_STATISTICS} + ,{"strip-local-absolute", no_argument, NULL, OPTION_STRIP_LOCAL_ABSOLUTE} + ,{"version", no_argument, NULL, OPTION_VERSION} + ,{"verbose", no_argument, NULL, OPTION_VERBOSE} + ,{"target-help", no_argument, NULL, OPTION_TARGET_HELP} + ,{"traditional-format", no_argument, NULL, OPTION_TRADITIONAL_FORMAT} + ,{"warn", no_argument, NULL, OPTION_WARN} + }; + + /* 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 = 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 = 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 explicitly 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 (); + verbose = 1; + break; + } + else + as_bad (_("unrecognized option -%c%s"), optc, optarg ? optarg : ""); + /* 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. */ + printf (_("GNU assembler %s\n"), BFD_VERSION_STRING); + printf (_("Copyright 2005 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'; + i = bfd_scan_vma (s, (const char **) NULL, 0); + n = 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 = 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 'g': + /* Some backends, eg Alpha and Mips, use the -g switch for their + own purposes. So we check here for an explicit -g and allow + the backend to decide if it wants to process it. */ + if ( old_argv[optind - 1][1] == 'g' + && md_parse_option (optc, optarg)) + continue; + + if (md_debug_format_selector) + debug_type = md_debug_format_selector (& use_gnu_debug_info_extensions); + else if (IS_ELF) + debug_type = DEBUG_DWARF2; + else + debug_type = DEBUG_STABS; + break; + + case OPTION_GSTABS_PLUS: + use_gnu_debug_info_extensions = 1; + /* Fall through. */ + 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; + +#if defined OBJ_ELF || defined OBJ_MAYBE_ELF + case OPTION_EXECSTACK: + flag_execstack = 1; + flag_noexecstack = 0; + break; + + case OPTION_NOEXECSTACK: + flag_noexecstack = 1; + flag_execstack = 0; + break; +#endif + case 'Z': + flag_always_generate_output = 1; + break; + + case OPTION_AL: + listing |= LISTING_LISTING; + if (optarg) + listing_filename = xstrdup (optarg); + break; + + case OPTION_ALTERNATE: + optarg = old_argv [optind - 1]; + while (* optarg == '-') + optarg ++; + + if (strcmp (optarg, "alternate") == 0) + { + flag_macro_alternate = 1; + break; + } + optarg ++; + /* Fall through. */ + + case 'a': + if (optarg) + { + if (optarg != old_argv[optind] && optarg[-1] == '=') + --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; + + case OPTION_REDUCE_MEMORY_OVERHEADS: + /* The only change we make at the moment is to reduce + the size of the hash tables that we use. */ + set_gas_hash_table_size (4051); + break; + + case OPTION_HASH_TABLE_SIZE: + { + unsigned long new_size; + + new_size = strtoul (optarg, NULL, 0); + if (new_size) + set_gas_hash_table_size (new_size); + else + as_fatal (_("--hash-size needs a numeric argument")); + break; + } + } + } + + free (shortopts); + free (longopts); + + *pargc = new_argc; + *pargv = new_argv; + +#ifdef md_after_parse_args + md_after_parse_args (); +#endif +} + +static void +dump_statistics (void) +{ +#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 +} + +#ifndef OBJ_VMS +static void +close_output_file (void) +{ + output_file_close (out_file_name); +} +#endif + +/* The interface between the macro code and gas expression handling. */ + +static int +macro_expr (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_and_evaluate (&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; +} + +/* 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 (int argc, char ** argv) +{ + int saw_a_file = 0; + flagword applicable; + + need_pass_2 = 0; + + /* 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); + + subseg_set (text_section, 0); + + /* This may add symbol table entries, which requires having an open BFD, + and sections already created. */ + 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 (""); +} + + +int +main (int argc, char ** argv) +{ + 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); + + expandargv (&argc, &argv); + + 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 (); + bfd_init (); + bfd_set_error_program_name (myname); + +#ifdef USE_EMULATIONS + select_emulation_mode (argc, argv); +#endif + + PROGRESS (1); + /* Call parse_args before any of the init/begin functions + so that switches like --hash-size can be honored. */ + parse_args (&argc, &argv); + symbol_begin (); + frag_init (); + subsegs_begin (); + read_begin (); + input_scrub_begin (); + expr_begin (); + +#ifndef OBJ_VMS /* Does its own file handling. */ + /* It has to be called after dump_statistics (). */ + xatexit (close_output_file); +#endif + + if (flag_print_statistics) + xatexit (dump_statistics); + + macro_strip_at = 0; +#ifdef TC_I960 + macro_strip_at = flag_mri; +#endif + + macro_init (flag_macro_alternate, flag_mri, macro_strip_at, macro_expr); + + PROGRESS (1); + + output_file_create (out_file_name); + assert (stdoutput != 0); + +#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 defined OBJ_ELF || defined OBJ_MAYBE_ELF + if ((flag_execstack || flag_noexecstack) + && OUTPUT_FLAVOR == bfd_target_elf_flavour) + { + segT gnustack; + + gnustack = subseg_new (".note.GNU-stack", 0); + bfd_set_section_flags (stdoutput, gnustack, + SEC_READONLY | (flag_execstack ? SEC_CODE : 0)); + + } +#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 we constructed dwarf2 .eh_frame info, either via .cfi + directives from the user or by the backend, emit it now. */ + cfi_finish (); + + if (seen_at_least_1_file () + && (flag_always_generate_output || had_errors () == 0)) + keep_it = 1; + else + keep_it = 0; + + /* 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 (); + + if (keep_it) + write_object_file (); + +#ifndef NO_LISTING + listing_print (listing_filename); +#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_if_ordinary (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); +} diff --git a/contrib/binutils-2.17/gas/as.h b/contrib/binutils-2.17/gas/as.h new file mode 100644 index 0000000000..2f92c2ed77 --- /dev/null +++ b/contrib/binutils-2.17/gas/as.h @@ -0,0 +1,665 @@ +/* as.h - global header file + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005 + 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, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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__ */ + +/* 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 + +/* 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 + +#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 + +#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 +#define assert(P) \ + ((void) ((P) ? 0 : (as_assert (__FILE__, __LINE__, __PRETTY_FUNCTION__), 0))) +#undef abort +#define abort() as_abort (__FILE__, __LINE__, __PRETTY_FUNCTION__) + +/* Now GNU header files... */ +#include "ansidecl.h" +#include "bfd.h" +#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_ENVIRON +extern char **environ; +#endif +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#ifdef NEED_DECLARATION_FFS +extern int ffs (int); +#endif +#ifdef NEED_DECLARATION_FREE +extern void free (); +#endif +#ifdef NEED_DECLARATION_MALLOC +extern PTR malloc (); +extern PTR realloc (); +#endif +#ifdef NEED_DECLARATION_STRSTR +extern char *strstr (); +#endif + +#if !HAVE_DECL_VSNPRINTF +extern int vsnprintf(char *, size_t, const char *, va_list); +#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 */ + +extern bfd *stdoutput; +typedef bfd_vma addressT; +typedef bfd_signed_vma offsetT; + +/* 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 elsewhere. */ +#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.*/ + +typedef asection *segT; +#define SEG_NORMAL(SEG) ( (SEG) != absolute_section \ + && (SEG) != undefined_section \ + && (SEG) != reg_section \ + && (SEG) != expr_section) +typedef int subsegT; + +/* What subseg we are accessing now? */ +COMMON subsegT now_subseg; + +/* Segment our instructions emit to. */ +COMMON segT now_seg; + +#define segment_name(SEG) bfd_get_section_name (stdoutput, SEG) + +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 + +enum _relax_state +{ + /* Dummy frag used by listing code. */ + rs_dummy = 0, + + /* Variable chars to be repeated fr_offset times. + Fr_symbol unused. Used with fr_offset == 0 for a + constant length frag. */ + rs_fill, + + /* 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; + +struct relax_type +{ + /* Forward reach. Signed number. > 0. */ + offsetT rlx_forward; + /* Backward reach. Signed number. < 0. */ + offsetT 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; + +/* 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; + +/* TRUE if .note.GNU-stack section with SEC_CODE should be created */ +COMMON int flag_execstack; + +/* TRUE if .note.GNU-stack section with SEC_CODE should be created */ +COMMON int flag_noexecstack; + +/* 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; +extern int use_gnu_debug_info_extensions; + +/* Maximum level of macro nesting. */ +extern int max_macro_nest; + +/* Verbosity level. */ +extern int verbose; + +/* 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) (int); + /* Value to pass to handler */ + int poc_val; +}; + +typedef struct _pseudo_type pseudo_typeS; + +#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 (const char *format, ...) +#define PRINTF_WHERE_LIKE(FCN) void FCN (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 (const char *, int, const char *); +void as_abort (const char *, int, const char *) ATTRIBUTE_NORETURN; +void sprint_value (char *, addressT); +int had_errors (void); +int had_warnings (void); +void as_warn_value_out_of_range (char *, offsetT, offsetT, offsetT, char *, unsigned); +void as_bad_value_out_of_range (char *, offsetT, offsetT, offsetT, char *, unsigned); +void print_version_id (void); +char * app_push (void); +char * atof_ieee (char *, int, LITTLENUM_TYPE *); +char * input_scrub_include_file (char *, char *); +void input_scrub_insert_line (const char *); +void input_scrub_insert_file (char *); +char * input_scrub_new_file (char *); +char * input_scrub_next_buffer (char **bufp); +int do_scrub_chars (int (*get) (char *, int), char *, int); +int gen_to_words (LITTLENUM_TYPE *, int, long); +int had_err (void); +int ignore_input (void); +void cond_finish_check (int); +void cond_exit_macro (int); +int seen_at_least_1_file (void); +void app_pop (char *); +void as_perror (const char *, const char *); +void as_where (char **, unsigned int *); +void bump_line_counters (void); +void do_scrub_begin (int); +void input_scrub_begin (void); +void input_scrub_close (void); +void input_scrub_end (void); +int new_logical_line (char *, int); +void subsegs_begin (void); +void subseg_change (segT, int); +segT subseg_new (const char *, subsegT); +segT subseg_force_new (const char *, subsegT); +void subseg_set (segT, subsegT); +int subseg_text_p (segT); +int seg_not_empty_p (segT); +void start_dependencies (char *); +void register_dependency (char *); +void print_dependencies (void); +segT subseg_get (const char *, int); + +struct expressionS; +struct fix; +typedef struct symbol symbolS; +struct relax_type; +typedef struct frag fragS; + +/* literal.c */ +valueT add_to_literal_pool (symbolS *, valueT, segT, int); + +int check_eh_frame (struct expressionS *, unsigned int *); +int eh_frame_estimate_size_before_relax (fragS *); +int eh_frame_relax_frag (fragS *); +void eh_frame_convert_frag (fragS *); +int generic_force_reloc (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; +#define DOLLAR_AMBIGU 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 DOLLAR_AMBIGU +#define DOLLAR_AMBIGU 0 +#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, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#ifdef HAVE_LOCALE_H +# ifndef ENABLE_NLS + /* The Solaris version of locale.h always includes libintl.h. If we have + been configured with --disable-nls then ENABLE_NLS will not be defined + and the dummy definitions of bindtextdomain (et al) below will conflict + with the defintions in libintl.h. So we define these values to prevent + the bogus inclusion of libintl.h. */ +# define _LIBINTL_H +# define _LIBGETTEXT_H +# endif +# 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.17/gas/atof-generic.c b/contrib/binutils-2.17/gas/atof-generic.c new file mode 100644 index 0000000000..6a5c2f15b3 --- /dev/null +++ b/contrib/binutils-2.17/gas/atof-generic.c @@ -0,0 +1,616 @@ +/* atof_generic.c - turn a string of digits into a Flonum + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2000, + 2001, 2003, 2005 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, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 (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 (/* 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) */ + maximum_useful_digits = (((precision - 2)) + * ( (LITTLENUM_NUMBER_OF_BITS)) + * 1000000 / 3321928) + + 2; /* 2 :: guard digits. */ + + 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); + + more_than_enough_bits_for_digits + = (number_of_digits_to_use * 3321928 / 1000000 + 1); + + 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 successful, 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.17/gas/bignum.h b/contrib/binutils-2.17/gas/bignum.h new file mode 100644 index 0000000000..d9e0429dde --- /dev/null +++ b/contrib/binutils-2.17/gas/bignum.h @@ -0,0 +1,41 @@ +/* bignum.h-arbitrary precision integers + Copyright 1987, 1992, 2003, 2005 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, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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; diff --git a/contrib/binutils-2.17/gas/bit_fix.h b/contrib/binutils-2.17/gas/bit_fix.h new file mode 100644 index 0000000000..64be49b430 --- /dev/null +++ b/contrib/binutils-2.17/gas/bit_fix.h @@ -0,0 +1,48 @@ +/* bit_fix.h + Copyright 1987, 1992, 2000, 2001, 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, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 possibility 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.17/gas/cond.c b/contrib/binutils-2.17/gas/cond.c new file mode 100644 index 0000000000..d6c32acc25 --- /dev/null +++ b/contrib/binutils-2.17/gas/cond.c @@ -0,0 +1,576 @@ +/* cond.c - conditional assembly pseudo-ops, and .include + Copyright 1990, 1991, 1992, 1993, 1995, 1997, 1998, 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, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 (struct conditional_frame *cframe); +static char *get_mri_string (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 (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) || symbol_equated_p (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 (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_and_evaluate (&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 (); +} + +/* Performs the .ifb (test_blank == 1) and + the .ifnb (test_blank == 0) pseudo op. */ + +void +s_ifb (int test_blank) +{ + struct conditional_frame cframe; + + initialize_cframe (&cframe); + + if (cframe.dead_tree) + cframe.ignoring = 1; + else + { + int is_eol; + + SKIP_WHITESPACE (); + is_eol = is_end_of_line[(unsigned char) *input_line_pointer]; + cframe.ignoring = (test_blank == !is_eol); + } + + 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); + + ignore_rest_of_line (); +} + +/* Get a string for the MRI IFC or IFNC pseudo-ops. */ + +static char * +get_mri_string (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 (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 (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_and_evaluate (&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 (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 (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 (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 (void) +{ + 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 (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 (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 (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.17/gas/config.in b/contrib/binutils-2.17/gas/config.in new file mode 100644 index 0000000000..b15d8024ab --- /dev/null +++ b/contrib/binutils-2.17/gas/config.in @@ -0,0 +1,318 @@ +/* config.in. Generated from configure.in by autoheader. */ + +/* Define if using AIX 5.2 value for C_WEAKEXT. */ +#undef AIX_WEAK_SUPPORT + +/* assert broken? */ +#undef BROKEN_ASSERT + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +#undef CRAY_STACKSEG_END + +/* Compiling cross-assembler? */ +#undef CROSS_COMPILE + +/* Define to 1 if using `alloca.c'. */ +#undef C_ALLOCA + +/* Default architecture. */ +#undef DEFAULT_ARCH + +/* Default CRIS architecture. */ +#undef DEFAULT_CRIS_ARCH + +/* Default emulation. */ +#undef DEFAULT_EMULATION + +/* Supported emulations. */ +#undef EMULATIONS + +/* Define to 1 if NLS is requested */ +#undef ENABLE_NLS + +/* Define to 1 if you have `alloca', as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#undef HAVE_ALLOCA_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARGZ_H + +/* Define to 1 if you have the `dcgettext' function. */ +#undef HAVE_DCGETTEXT + +/* Is the prototype for getopt in in the expected format? */ +#undef HAVE_DECL_GETOPT + +/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you + don't. */ +#undef HAVE_DECL_VSNPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_ERRNO_H + +/* Define to 1 if you have the `getcwd' function. */ +#undef HAVE_GETCWD + +/* Define to 1 if you have the `getpagesize' function. */ +#undef HAVE_GETPAGESIZE + +/* Define as 1 if you have gettext and don't want to use GNU gettext. */ +#undef HAVE_GETTEXT + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define if your locale.h file contains LC_MESSAGES. */ +#undef HAVE_LC_MESSAGES + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the `munmap' function. */ +#undef HAVE_MUNMAP + +/* Define to 1 if you have the header file. */ +#undef HAVE_NL_TYPES_H + +/* Define to 1 if you have the `putenv' function. */ +#undef HAVE_PUTENV + +/* Define to 1 if you have the `remove' function. */ +#undef HAVE_REMOVE + +/* Define to 1 if you have the `sbrk' function. */ +#undef HAVE_SBRK + +/* Define to 1 if you have the `setenv' function. */ +#undef HAVE_SETENV + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDARG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the stpcpy function */ +#undef HAVE_STPCPY + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `unlink' function. */ +#undef HAVE_UNLINK + +/* Define to 1 if you have the header file. */ +#undef HAVE_VALUES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_VARARGS_H + +/* Define to 1 if you have the `__argz_count' function. */ +#undef HAVE___ARGZ_COUNT + +/* Define to 1 if you have the `__argz_next' function. */ +#undef HAVE___ARGZ_NEXT + +/* Define to 1 if you have the `__argz_stringify' function. */ +#undef HAVE___ARGZ_STRINGIFY + +/* Using i386 COFF? */ +#undef I386COFF + +/* Using m68k COFF? */ +#undef M68KCOFF + +/* Using m88k COFF? */ +#undef M88KCOFF + +/* Default CPU for MIPS targets. */ +#undef MIPS_CPU_STRING_DEFAULT + +/* Generate 64-bit code by default on MIPS targets. */ +#undef MIPS_DEFAULT_64BIT + +/* Choose a default ABI for MIPS targets. */ +#undef MIPS_DEFAULT_ABI + +/* Define if environ is not declared in system header files. */ +#undef NEED_DECLARATION_ENVIRON + +/* Define if errno is not declared in system header files. */ +#undef NEED_DECLARATION_ERRNO + +/* Define if ffs is not declared in system header files. */ +#undef NEED_DECLARATION_FFS + +/* Define if free is not declared in system header files. */ +#undef NEED_DECLARATION_FREE + +/* Define if malloc is not declared in system header files. */ +#undef NEED_DECLARATION_MALLOC + +/* Define if sbrk is not declared in system header files. */ +#undef NEED_DECLARATION_SBRK + +/* Define if strstr is not declared in system header files. */ +#undef NEED_DECLARATION_STRSTR + +/* a.out support? */ +#undef OBJ_MAYBE_AOUT + +/* b.out support? */ +#undef OBJ_MAYBE_BOUT + +/* COFF support? */ +#undef OBJ_MAYBE_COFF + +/* ECOFF support? */ +#undef OBJ_MAYBE_ECOFF + +/* ELF support? */ +#undef OBJ_MAYBE_ELF + +/* generic support? */ +#undef OBJ_MAYBE_GENERIC + +/* IEEE support? */ +#undef OBJ_MAYBE_IEEE + +/* SOM support? */ +#undef OBJ_MAYBE_SOM + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define if defaulting to ELF on SCO 5. */ +#undef SCO_ELF + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +#undef STACK_DIRECTION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Using strict COFF? */ +#undef STRICTCOFF + +/* Target alias. */ +#undef TARGET_ALIAS + +/* Define as 1 if big endian. */ +#undef TARGET_BYTES_BIG_ENDIAN + +/* Canonical target. */ +#undef TARGET_CANONICAL + +/* Target CPU. */ +#undef TARGET_CPU + +/* Target OS. */ +#undef TARGET_OS + +/* Define if default target is PowerPC Solaris. */ +#undef TARGET_SOLARIS_COMMENT + +/* Define if target is Symbian OS. */ +#undef TARGET_SYMBIAN + +/* Target vendor. */ +#undef TARGET_VENDOR + +/* Use emulation support? */ +#undef USE_EMULATIONS + +/* Allow use of E_MIPS_ABI_O32 on MIPS targets. */ +#undef USE_E_MIPS_ABI_O32 + +/* Using cgen code? */ +#undef USING_CGEN + +/* Version number of package */ +#undef VERSION + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to `long' if does not define. */ +#undef off_t + +/* Define to `unsigned' if does not define. */ +#undef size_t diff --git a/contrib/binutils-2.17/gas/config/atof-ieee.c b/contrib/binutils-2.17/gas/config/atof-ieee.c new file mode 100644 index 0000000000..bf842e1717 --- /dev/null +++ b/contrib/binutils-2.17/gas/config/atof-ieee.c @@ -0,0 +1,700 @@ +/* atof_ieee.c - turn a Flonum into an IEEE floating point number + Copyright 1987, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001, 2005 + 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, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#include "as.h" + +/* Flonums returned here. */ +extern FLONUM_TYPE generic_floating_point_number; + +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 (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 (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 (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 (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 (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)); + } + } + return return_value; +} + +#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.17/gas/config/obj-elf.c b/contrib/binutils-2.17/gas/config/obj-elf.c new file mode 100644 index 0000000000..f922149cae --- /dev/null +++ b/contrib/binutils-2.17/gas/config/obj-elf.c @@ -0,0 +1,2265 @@ +/* ELF object file format + Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005 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, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#define OBJ_HEADER "obj-elf.h" +#include "as.h" +#include "safe-ctype.h" +#include "subsegs.h" +#include "obstack.h" +#include "struc-symbol.h" +#include "dwarf2dbg.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 + +#ifdef TC_I386 +#include "elf/x86-64.h" +#endif + +static void obj_elf_line (int); +static void obj_elf_size (int); +static void obj_elf_type (int); +static void obj_elf_ident (int); +static void obj_elf_weak (int); +static void obj_elf_local (int); +static void obj_elf_visibility (int); +static void obj_elf_symver (int); +static void obj_elf_subsection (int); +static void obj_elf_popsection (int); +static void obj_elf_tls_common (int); +static void obj_elf_lcomm (int); +static void obj_elf_struct (int); + +static const pseudo_typeS elf_pseudo_table[] = +{ + {"comm", obj_elf_common, 0}, + {"common", obj_elf_common, 1}, + {"ident", obj_elf_ident, 0}, + {"lcomm", obj_elf_lcomm, 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 (*) (int)) &obj_elf_vtable_inherit, 0}, + {"vtable_entry", (void (*) (int)) &obj_elf_vtable_entry, 0}, + + /* These are used for dwarf. */ + {"2byte", cons, 2}, + {"4byte", cons, 4}, + {"8byte", cons, 8}, + /* These are used for dwarf2. */ + { "file", (void (*) (int)) dwarf2_directive_file, 0 }, + { "loc", dwarf2_directive_loc, 0 }, + { "loc_mark_labels", dwarf2_directive_loc_mark_labels, 0 }, + + /* We need to trap the section changing calls to handle .previous. */ + {"data", obj_elf_data, 0}, + {"offset", obj_elf_struct, 0}, + {"struct", obj_elf_struct, 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. */ + +asection *elf_com_section_ptr; + +void +elf_begin (void) +{ + asection *s; + + /* Add symbols for the known sections to the symbol table. */ + s = bfd_get_section_by_name (stdoutput, TEXT_SECTION_NAME); + symbol_table_insert (section_symbol (s)); + s = bfd_get_section_by_name (stdoutput, DATA_SECTION_NAME); + symbol_table_insert (section_symbol (s)); + s = bfd_get_section_by_name (stdoutput, BSS_SECTION_NAME); + symbol_table_insert (section_symbol (s)); + elf_com_section_ptr = bfd_com_section_ptr; +} + +void +elf_pop_insert (void) +{ + pop_insert (elf_pseudo_table); + if (ECOFF_DEBUGGING) + pop_insert (ecoff_debug_pseudo_table); +} + +static bfd_vma +elf_s_get_size (symbolS *sym) +{ + return S_GET_SIZE (sym); +} + +static void +elf_s_set_size (symbolS *sym, bfd_vma sz) +{ + S_SET_SIZE (sym, sz); +} + +static bfd_vma +elf_s_get_align (symbolS *sym) +{ + return S_GET_ALIGN (sym); +} + +static void +elf_s_set_align (symbolS *sym, bfd_vma align) +{ + S_SET_ALIGN (sym, align); +} + +int +elf_s_get_other (symbolS *sym) +{ + return elf_symbol (symbol_get_bfdsym (sym))->internal_elf_sym.st_other; +} + +static void +elf_s_set_other (symbolS *sym, int other) +{ + S_SET_OTHER (sym, other); +} + +static int +elf_sec_sym_ok_for_reloc (asection *sec) +{ + return obj_sec_sym_ok_for_reloc (sec); +} + +void +elf_file_symbol (const char *s, int appfile) +{ + if (!appfile + || symbol_rootP == NULL + || symbol_rootP->bsym == NULL + || (symbol_rootP->bsym->flags & BSF_FILE) == 0) + { + symbolS *sym; + + sym = symbol_new (s, absolute_section, 0, NULL); + 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, appfile); +#endif +} + +/* Called from read.c:s_comm after we've parsed .comm symbol, size. + Parse a possible alignment value. */ + +symbolS * +elf_common_parse (int ignore ATTRIBUTE_UNUSED, symbolS *symbolP, addressT size) +{ + addressT align = 0; + int is_local = symbol_get_obj (symbolP)->local; + + if (*input_line_pointer == ',') + { + char *save = input_line_pointer; + + input_line_pointer++; + SKIP_WHITESPACE (); + + if (*input_line_pointer == '"') + { + /* For sparc. Accept .common symbol, length, "bss" */ + input_line_pointer++; + /* Some use the dot, some don't. */ + if (*input_line_pointer == '.') + input_line_pointer++; + /* Some say data, some say bss. */ + if (strncmp (input_line_pointer, "bss\"", 4) == 0) + input_line_pointer += 4; + else if (strncmp (input_line_pointer, "data\"", 5) == 0) + input_line_pointer += 5; + else + { + char *p = input_line_pointer; + char c; + + while (*--p != '"') + ; + while (!is_end_of_line[(unsigned char) *input_line_pointer]) + if (*input_line_pointer++ == '"') + break; + c = *input_line_pointer; + *input_line_pointer = '\0'; + as_bad (_("bad .common segment %s"), p); + *input_line_pointer = c; + ignore_rest_of_line (); + return NULL; + } + /* ??? Don't ask me why these are always global. */ + is_local = 0; + } + else + { + input_line_pointer = save; + align = parse_align (is_local); + if (align == (addressT) -1) + return NULL; + } + } + + if (is_local) + { + bss_alloc (symbolP, size, align); + S_CLEAR_EXTERNAL (symbolP); + } + else + { + S_SET_VALUE (symbolP, size); + S_SET_ALIGN (symbolP, align); + S_SET_EXTERNAL (symbolP); + S_SET_SEGMENT (symbolP, elf_com_section_ptr); + } + + symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT; + + return symbolP; +} + +void +obj_elf_common (int is_common) +{ + if (flag_mri && is_common) + s_mri_common (0); + else + s_comm_internal (0, elf_common_parse); +} + +static void +obj_elf_tls_common (int ignore ATTRIBUTE_UNUSED) +{ + symbolS *symbolP = s_comm_internal (0, elf_common_parse); + + if (symbolP) + symbol_get_bfdsym (symbolP)->flags |= BSF_THREAD_LOCAL; +} + +static void +obj_elf_lcomm (int ignore ATTRIBUTE_UNUSED) +{ + symbolS *symbolP = s_comm_internal (0, s_lcomm_internal); + + if (symbolP) + symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT; +} + +static void +obj_elf_local (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 (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 (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; + +static bfd_boolean +get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf) +{ + const char *gname = inf; + const char *group_name = elf_group_name (sec); + + return (group_name == gname + || (group_name != NULL + && gname != NULL + && strcmp (group_name, gname) == 0)); +} + +/* 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. */ + +void +obj_elf_change_section (const char *name, + int type, + int attr, + int entsize, + const char *group_name, + int linkonce, + int push) +{ + asection *old_sec; + segT sec; + flagword flags; + const struct elf_backend_data *bed; + const struct bfd_elf_special_section *ssect; + +#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_if (stdoutput, name, get_section, + (void *) group_name); + if (old_sec) + { + sec = old_sec; + subseg_set (sec, 0); + } + else + sec = subseg_force_new (name, 0); + + bed = get_elf_backend_data (stdoutput); + ssect = (*bed->get_sec_type_attr) (stdoutput, sec); + + if (ssect != NULL) + { + bfd_boolean override = FALSE; + + if (type == SHT_NULL) + type = ssect->type; + else if (type != ssect->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. Also for x86-64 large bss + sections, gcc, as of 2005-07-06, will emit + + .section .lbss,"aw",@progbits + + "@progbits" is incorrect. */ +#ifdef TC_I386 + && (bed->s->arch_size != 64 + || !(ssect->attr & SHF_X86_64_LARGE)) +#endif + && ssect->type != SHT_INIT_ARRAY + && ssect->type != SHT_FINI_ARRAY + && ssect->type != SHT_PREINIT_ARRAY) + { + /* We allow to specify any type for a .note section. */ + if (ssect->type != SHT_NOTE) + as_warn (_("setting incorrect section type for %s"), + name); + } + else + { + as_warn (_("ignoring incorrect section type for %s"), + name); + type = ssect->type; + } + } + + if (old_sec == NULL && (attr & ~ssect->attr) != 0) + { + /* As a GNU extension, we permit a .note section to be + allocatable. If the linker sees an allocatable .note + section, it will create a PT_NOTE segment in the output + file. We also allow "x" for .note.GNU-stack. */ + if (ssect->type == SHT_NOTE + && (attr == SHF_ALLOC || attr == SHF_EXECINSTR)) + ; + /* Allow different SHF_MERGE and SHF_STRINGS if we have + something like .rodata.str. */ + else if (ssect->suffix_length == -2 + && name[ssect->prefix_length] == '.' + && (attr + & ~ssect->attr + & ~SHF_MERGE + & ~SHF_STRINGS) == 0) + ; + /* .interp, .strtab and .symtab can have SHF_ALLOC. */ + else if (attr == SHF_ALLOC + && (strcmp (name, ".interp") == 0 + || strcmp (name, ".strtab") == 0 + || strcmp (name, ".symtab") == 0)) + override = TRUE; + /* .note.GNU-stack can have SHF_EXECINSTR. */ + else if (attr == SHF_EXECINSTR + && strcmp (name, ".note.GNU-stack") == 0) + override = TRUE; + else + { + if (group_name == NULL) + as_warn (_("setting incorrect section attributes for %s"), + name); + override = TRUE; + } + } + if (!override && old_sec == NULL) + attr |= ssect->attr; + } + + /* 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 (linkonce) + flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; + + if (old_sec == NULL) + { + symbolS *secsym; + + elf_section_type (sec) = type; + elf_section_flags (sec) = attr; + + /* Prevent SEC_HAS_CONTENTS from being inadvertently set. */ + if (type == SHT_NOBITS) + seg_info (sec)->bss = 1; + + 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 (type != SHT_NULL + && (unsigned) type != elf_section_type (old_sec)) + as_warn (_("ignoring changed section type for %s"), name); + + 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); + } + } + +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif +} + +static int +obj_elf_parse_section_letters (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_fatal ("%s", bad_msg); + } + break; + } + str++, len--; + } + + return attr; +} + +static int +obj_elf_section_word (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 (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; + if (len == 4 && strncmp (str, "note", 4) == 0) + return SHT_NOTE; + if (len == 10 && strncmp (str, "init_array", 10) == 0) + return SHT_INIT_ARRAY; + if (len == 10 && strncmp (str, "fini_array", 10) == 0) + return SHT_FINI_ARRAY; + if (len == 13 && strncmp (str, "preinit_array", 13) == 0) + return SHT_PREINIT_ARRAY; + +#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 (void) +{ + 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_bad (_("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'; +#ifdef tc_canonicalize_section_name + name = tc_canonicalize_section_name (name); +#endif + input_line_pointer = end; + } + SKIP_WHITESPACE (); + return name; +} + +void +obj_elf_section (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_bad (_("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 (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 (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 +} + +/* Change to the *ABS* section. */ + +void +obj_elf_struct (int i) +{ +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + previous_section = now_seg; + previous_subsection = now_subseg; + s_struct (i); + +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif +} + +static void +obj_elf_subsection (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 (void) +{ + previous_section = now_seg; + previous_subsection = now_subseg; +} + +void +obj_elf_previous (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 (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 (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 (NULL, 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 (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 (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 (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 (void) +{ +#ifdef NEED_ECOFF_DEBUG + if (ECOFF_DEBUGGING) + ecoff_read_begin_hook (); +#endif +} + +void +elf_obj_symbol_new_hook (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 (symbolS *dest, symbolS *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 = 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 (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 = 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, i_note.namesz, sizeof (e_note.namesz)); + p = frag_more (sizeof (e_note.descsz)); + md_number_to_chars (p, i_note.descsz, sizeof (e_note.descsz)); + p = frag_more (sizeof (e_note.type)); + md_number_to_chars (p, 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 (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 = 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 (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; + else if (strcmp (typename, "notype") == 0 + || strcmp (typename, "STT_NOTYPE") == 0) + ; +#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 (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 (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, NULL); + stabstr_name = 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 (bfd *abfd, asection *sec, void *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 = 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, nsyms, p + 6); + bfd_h_put_32 (abfd, strsz, 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 (symbolS *sym, struct ecoff_extr *ext) +{ + symbol_get_bfdsym (sym)->udata.p = 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 (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. */ + +static void +elf_set_index (asymbol *sym ATTRIBUTE_UNUSED, + bfd_size_type indx ATTRIBUTE_UNUSED) +{ +} + +#endif /* NEED_ECOFF_DEBUG */ + +void +elf_frob_symbol (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 +} + +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 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf) +{ + struct group_list *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 (void) +{ + struct group_list list; + unsigned int i; + + bfd_map_over_sections (stdoutput, adjust_stab_sections, NULL); + + /* Go find section groups. */ + list.num_group = 0; + list.head = NULL; + list.elt_count = NULL; + bfd_map_over_sections (stdoutput, build_group_lists, &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; + bfd_size_type size; + + 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 ())); + } + elf_section_type (s) = SHT_GROUP; + + /* 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; + + size = 4 * (list.elt_count[i] + 1); + bfd_set_section_size (stdoutput, s, size); + s->contents = (unsigned char *) frag_more (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 (void) +{ + 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 (void) +{ +#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 != 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, void *); + SET (external_pdr, cbPdOffset, void *); + SET (external_sym, cbSymOffset, void *); + SET (external_opt, cbOptOffset, void *); + SET (external_aux, cbAuxOffset, union aux_ext *); + SET (ss, cbSsOffset, char *); + SET (external_fdr, cbFdOffset, void *); + SET (external_rfd, cbRfdOffset, void *); + /* 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? */ + bfd_set_section_size + (stdoutput, sec, 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, buf, 0, 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 plagiarized 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 (void) +{ + + 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 = 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, i_note.namesz, 4); + + p = frag_more (sizeof (i_note.descsz)); + md_number_to_chars (p, i_note.descsz, 4); + + p = frag_more (sizeof (i_note.type)); + md_number_to_chars (p, 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 (void) +{ +#ifdef NEED_ECOFF_DEBUG + return (!ECOFF_DEBUGGING); +#else + return 1; +#endif +} + +static void +elf_init_stab_section (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.17/gas/config/obj-elf.h b/contrib/binutils-2.17/gas/config/obj-elf.h new file mode 100644 index 0000000000..7ff9ef09aa --- /dev/null +++ b/contrib/binutils-2.17/gas/config/obj-elf.h @@ -0,0 +1,258 @@ +/* ELF object file format. + Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004 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, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 (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 (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_sec_set_private_data +#define obj_sec_set_private_data(B, S) \ + if (! BFD_SEND ((B), _new_section_hook, ((B), (S)))) \ + as_fatal (_("can't allocate ELF private section data: %s"), \ + bfd_errmsg (bfd_get_error ())) +#endif + +#ifndef obj_frob_file +#define obj_frob_file elf_frob_file +#endif +extern void elf_frob_file (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 (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 (void); + +/* If the target doesn't have special processing for labels, take care of + dwarf2 output at the object file level. */ +#ifndef tc_frob_label +#include "dwarf2dbg.h" +#define obj_frob_label dwarf2_emit_label +#endif + +#ifndef obj_app_file +#define obj_app_file elf_file_symbol +#endif +extern void elf_file_symbol (const char *, int); + +extern void obj_elf_section_change_hook (void); + +extern void obj_elf_section (int); +extern void obj_elf_previous (int); +extern void obj_elf_version (int); +extern void obj_elf_common (int); +extern void obj_elf_data (int); +extern void obj_elf_text (int); +extern void obj_elf_change_section + (const char *, int, int, int, const char *, int, int); +extern struct fix *obj_elf_vtable_inherit (int); +extern struct fix *obj_elf_vtable_entry (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 (void); +#ifndef obj_read_begin_hook +#define obj_read_begin_hook elf_obj_read_begin_hook +#endif + +void elf_obj_symbol_new_hook (symbolS *); +#ifndef obj_symbol_new_hook +#define obj_symbol_new_hook elf_obj_symbol_new_hook +#endif + +void elf_copy_symbol_attributes (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 (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 (symbolS *, int *); +#ifndef obj_frob_symbol +#define obj_frob_symbol(symp, punt) elf_frob_symbol (symp, &punt) +#endif + +extern void elf_pop_insert (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 +struct ecoff_extr; +extern void elf_ecoff_set_ext (symbolS *, struct ecoff_extr *); +#endif +extern asection *elf_com_section_ptr; +extern symbolS * elf_common_parse (int ignore ATTRIBUTE_UNUSED, symbolS *symbolP, + addressT size); + +#endif /* _OBJ_ELF_H */ diff --git a/contrib/binutils-2.17/gas/config/tc-i386.c b/contrib/binutils-2.17/gas/config/tc-i386.c new file mode 100644 index 0000000000..be384bc99a --- /dev/null +++ b/contrib/binutils-2.17/gas/config/tc-i386.c @@ -0,0 +1,7338 @@ +/* i386.c -- Assemble code for the Intel 80386 + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004, 2005, 2006 + 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, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +/* Intel 80386 machine specific gas. + Written by Eliot Dresselhaus (eliot@mgm.mit.edu). + x86_64 support by Jan Hubicka (jh@suse.cz) + VIA PadLock support by Michal Ludvig (mludvig@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 "dw2gencfi.h" +#include "opcode/i386.h" +#include "elf/x86-64.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 + +#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)); +#ifdef TE_PE +static void pe_directive_secrel PARAMS ((int)); +#endif +static void signed_cons 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 +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) +static void handle_large_common (int small ATTRIBUTE_UNUSED); +#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 */ + enum bfd_reloc_code_real 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. */ +const char extra_symbol_chars[] = "*%-([" +#ifdef LEX_AT + "@" +#endif +#ifdef LEX_QM + "?" +#endif + ; + +#if (defined (TE_I386AIX) \ + || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \ + && !defined (TE_GNU) \ + && !defined (TE_LINUX) \ + && !defined (TE_NETWARE) \ + && !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. The option + --divide will remove '/' from this list. */ +const char *i386_comment_chars = "#/"; +#define SVR4_COMMENT_CHARS 1 +#define PREFIX_SEPARATOR '\\' + +#else +const char *i386_comment_chars = "#"; +#define PREFIX_SEPARATOR '/' +#endif + +/* 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[] = "#/"; + +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 characters 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 unsigned int object_64bit; +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 optimize code alignment. */ +int optimize_align_code = 1; + +/* Non-zero to quieten some warnings. */ +static int quiet_warnings = 0; + +/* CPU name. */ +static const char *cpu_arch_name = NULL; +static const char *cpu_sub_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_". */ +static symbolS *GOT_symbol; + +/* The dwarf2 return column, adjusted for 32 or 64 bit. */ +unsigned int x86_dwarf2_return_column; + +/* The dwarf2 data alignment, adjusted for 32 or 64 bit. */ +int x86_cie_data_alignment; + +/* 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 }, + {"i686", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686 }, + {"pentium", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586 }, + {"pentiumpro",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686 }, + {"pentiumii", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX }, + {"pentiumiii",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX|CpuMMX2|CpuSSE }, + {"pentium4", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2|CpuSSE|CpuSSE2 }, + {"prescott", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuPNI }, + {"k6", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX }, + {"k6_2", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX|Cpu3dnow }, + {"athlon", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA }, + {"sledgehammer",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuSledgehammer|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2 }, + {"opteron", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuSledgehammer|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2 }, + {".mmx", CpuMMX }, + {".sse", CpuMMX|CpuMMX2|CpuSSE }, + {".sse2", CpuMMX|CpuMMX2|CpuSSE|CpuSSE2 }, + {".sse3", CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3 }, + {".3dnow", CpuMMX|Cpu3dnow }, + {".3dnowa", CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA }, + {".padlock", CpuPadLock }, + {".pacifica", CpuSVME }, + {".svme", CpuSVME }, + {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}, + {"slong", signed_cons, 4}, + {"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}, +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + {"largecomm", handle_large_common, 0}, +#else + {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0}, + {"loc", dwarf2_directive_loc, 0}, + {"loc_mark_labels", dwarf2_directive_loc_mark_labels, 0}, +#endif +#ifdef TE_PE + {"secrel32", pe_directive_secrel, 0}, +#endif + {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; + unsigned int q; + + if (prefix >= REX_OPCODE && prefix < REX_OPCODE + 16 + && flag_code == CODE_64BIT) + { + if ((i.prefix[REX_PREFIX] & prefix & REX_MODE64) + || ((i.prefix[REX_PREFIX] & (REX_EXTX | REX_EXTY | REX_EXTZ)) + && (prefix & (REX_EXTX | REX_EXTY | REX_EXTZ)))) + ret = 0; + 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) + ret = 0; + } + + if (ret) + { + if (!i.prefix[q]) + ++i.prefixes; + i.prefix[q] |= prefix; + } + else + as_bad (_("same type of prefix used twice")); + + 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 = LONG_MNEM_SUFFIX; +} + +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) + allow_naked_reg = (intel_syntax + && (bfd_get_symbol_leading_char (stdoutput) != '\0')); + else + allow_naked_reg = (ask_naked_reg < 0); + + identifier_chars['%'] = intel_syntax && allow_naked_reg ? '%' : 0; + identifier_chars['$'] = intel_syntax ? '$' : 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) + { + if (*string != '.') + { + cpu_arch_name = cpu_arch[i].name; + cpu_sub_arch_name = NULL; + cpu_arch_flags = (cpu_arch[i].flags + | (flag_code == CODE_64BIT ? Cpu64 : CpuNo64)); + break; + } + if ((cpu_arch_flags | cpu_arch[i].flags) != cpu_arch_flags) + { + cpu_sub_arch_name = cpu_arch[i].name; + cpu_arch_flags |= cpu_arch[i].flags; + } + *input_line_pointer = e; + demand_empty_rest_of_line (); + return; + } + } + 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 (); +} + +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")); +} + +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 +#ifdef LEX_QM + identifier_chars['?'] = '?'; + operand_chars['?'] = '?'; +#endif + digit_chars['-'] = '-'; + mnemonic_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 (IS_ELF) + { + record_alignment (text_section, 2); + record_alignment (data_section, 2); + record_alignment (bss_section, 2); + } +#endif + + if (flag_code == CODE_64BIT) + { + x86_dwarf2_return_column = 16; + x86_cie_data_alignment = -8; + } + else + { + x86_dwarf2_return_column = 8; + x86_cie_data_alignment = -4; + } +} + +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))); +} + +static struct type_name + { + unsigned int mask; + char *tname; + } +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 */ + +static bfd_reloc_code_real_type +reloc (unsigned int size, + int pcrel, + int sign, + bfd_reloc_code_real_type other) +{ + if (other != NO_RELOC) + { + reloc_howto_type *reloc; + + if (size == 8) + switch (other) + { + case BFD_RELOC_X86_64_GOT32: + return BFD_RELOC_X86_64_GOT64; + break; + case BFD_RELOC_X86_64_PLTOFF64: + return BFD_RELOC_X86_64_PLTOFF64; + break; + case BFD_RELOC_X86_64_GOTPC32: + other = BFD_RELOC_X86_64_GOTPC64; + break; + case BFD_RELOC_X86_64_GOTPCREL: + other = BFD_RELOC_X86_64_GOTPCREL64; + break; + case BFD_RELOC_X86_64_TPOFF32: + other = BFD_RELOC_X86_64_TPOFF64; + break; + case BFD_RELOC_X86_64_DTPOFF32: + other = BFD_RELOC_X86_64_DTPOFF64; + break; + default: + break; + } + + /* Sign-checking 4-byte relocations in 16-/32-bit code is pointless. */ + if (size == 4 && flag_code != CODE_64BIT) + sign = -1; + + reloc = bfd_reloc_type_lookup (stdoutput, other); + if (!reloc) + as_bad (_("unknown relocation (%u)"), other); + else if (size != bfd_get_reloc_size (reloc)) + as_bad (_("%u-byte relocation cannot be applied to %u-byte field"), + bfd_get_reloc_size (reloc), + size); + else if (pcrel && !reloc->pc_relative) + as_bad (_("non-pc-relative relocation for pc-relative field")); + else if ((reloc->complain_on_overflow == complain_overflow_signed + && !sign) + || (reloc->complain_on_overflow == complain_overflow_unsigned + && sign > 0)) + as_bad (_("relocated field and relocation type differ in signedness")); + else + return other; + return NO_RELOC; + } + + 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; + case 8: return BFD_RELOC_64_PCREL; + } + as_bad (_("cannot do %u byte pc-relative relocation"), size); + } + else + { + if (sign > 0) + 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 (_("cannot do %s %u byte relocation"), + sign > 0 ? "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 (!IS_ELF) + 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; + + /* The x86_64 GOTPCREL are represented as 32bit PCrel relocations + and changed later by validate_fix. */ + if (GOT_symbol && fixP->fx_subsy == GOT_symbol + && fixP->fx_r_type == BFD_RELOC_32_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_386_TLS_GOTDESC + || fixP->fx_r_type == BFD_RELOC_386_TLS_DESC_CALL + || 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_DTPOFF64 + || fixP->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF + || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF32 + || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF64 + || fixP->fx_r_type == BFD_RELOC_X86_64_GOTOFF64 + || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC + || fixP->fx_r_type == BFD_RELOC_X86_64_TLSDESC_CALL + || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT + || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + return 0; +#endif + return 1; +} + +static int intel_float_operand PARAMS ((const char *mnemonic)); + +static int +intel_float_operand (mnemonic) + const char *mnemonic; +{ + /* Note that the value returned is meaningful only for opcodes with (memory) + operands, hence the code here is free to improperly handle opcodes that + have no operands (for better performance and smaller code). */ + + if (mnemonic[0] != 'f') + return 0; /* non-math */ + + switch (mnemonic[1]) + { + /* fclex, fdecstp, fdisi, femms, feni, fincstp, finit, fsetpm, and + the fs segment override prefix not currently handled because no + call path can make opcodes without operands get here */ + case 'i': + return 2 /* integer op */; + case 'l': + if (mnemonic[2] == 'd' && (mnemonic[3] == 'c' || mnemonic[3] == 'e')) + return 3; /* fldcw/fldenv */ + break; + case 'n': + if (mnemonic[2] != 'o' /* fnop */) + return 3; /* non-waiting control op */ + break; + case 'r': + if (mnemonic[2] == 's') + return 3; /* frstor/frstpm */ + break; + case 's': + if (mnemonic[2] == 'a') + return 3; /* fsave */ + if (mnemonic[2] == 't') + { + switch (mnemonic[3]) + { + case 'c': /* fstcw */ + case 'd': /* fstdw */ + case 'e': /* fstenv */ + case 's': /* fsts[gw] */ + return 3; + } + } + break; + case 'x': + if (mnemonic[2] == 'r' || mnemonic[2] == 's') + return 0; /* fxsave/fxrstor are not really math ops */ + break; + } + + return 1; +} + +/* 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) + && (strcmp (mnemonic, "invlpga") != 0) + && !((i.types[0] & Imm) && (i.types[1] & Imm))) + swap_operands (); + + if (i.imm_operands) + optimize_imm (); + + /* Don't optimize displacement for movabs since it only takes 64bit + displacement. */ + if (i.disp_operands + && (flag_code != CODE_64BIT + || strcmp (mnemonic, "movabs") != 0)) + 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) + { + if (i.reg_operands < 2 + && !i.suffix + && (~i.tm.opcode_modifier + & (No_bSuf + | No_wSuf + | No_lSuf + | No_sSuf + | No_xSuf + | No_qSuf))) + as_bad (_("ambiguous operand size for `%s'"), i.tm.name); + + 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) + { + expressionS *exp; + + if ((i.tm.cpu_flags & CpuPNI) && i.operands > 0) + { + /* These Intel Prescott New Instructions have the fixed + operands with an opcode suffix which is coded in the same + place as an 8-bit immediate field would be. Here we check + those operands and remove them afterwards. */ + unsigned int x; + + for (x = 0; x < i.operands; x++) + if (i.op[x].regs->reg_num != x) + as_bad (_("can't use register '%%%s' as operand %d in '%s'."), + i.op[x].regs->reg_name, x + 1, i.tm.name); + i.operands = 0; + } + + /* 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. */ + + 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."), + 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; + int supported; + const template *t; + + /* 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 + && (intel_syntax + || (*l != PREFIX_SEPARATOR + && *l != ','))) + { + as_bad (_("invalid character %s in mnemonic"), + output_invalid (*l)); + return NULL; + } + if (token_start == l) + { + if (!intel_syntax && *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 (current_templates->start->cpu_flags + & (flag_code != CODE_64BIT ? Cpu64 : CpuNo64)) + { + as_bad ((flag_code != CODE_64BIT + ? _("`%s' is only supported in 64-bit mode") + : _("`%s' is not supported in 64-bit mode")), + current_templates->start->name); + return NULL; + } + /* 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: + if (intel_syntax && (intel_float_operand (mnemonic) & 2)) + i.suffix = SHORT_MNEM_SUFFIX; + else + 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) == 1) + 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. */ + supported = 0; + for (t = current_templates->start; t < current_templates->end; ++t) + { + if (!((t->cpu_flags & ~(Cpu64 | CpuNo64)) + & ~(cpu_arch_flags & ~(Cpu64 | CpuNo64)))) + supported |= 1; + if (!(t->cpu_flags & (flag_code == CODE_64BIT ? CpuNo64 : Cpu64))) + supported |= 2; + } + if (!(supported & 2)) + { + as_bad (flag_code == CODE_64BIT + ? _("`%s' is not supported in 64-bit mode") + : _("`%s' is only supported in 64-bit mode"), + current_templates->start->name); + return NULL; + } + if (!(supported & 1)) + { + as_warn (_("`%s' is not supported on `%s%s'"), + current_templates->start->name, + cpu_arch_name, + cpu_sub_arch_name ? cpu_sub_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) + { + static templates override; + + for (t = current_templates->start; t < current_templates->end; ++t) + if (t->opcode_modifier & IsString) + break; + if (t >= current_templates->end) + { + as_bad (_("expecting string instruction after `%s'"), + expecting_string_instruction); + return NULL; + } + for (override.start = t; t < current_templates->end; ++t) + if (!(t->opcode_modifier & IsString)) + break; + override.end = t; + current_templates = &override; + } + + 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; + enum bfd_reloc_code_real 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, but don't + prevent matching a set of insns that only supports sizes other + than those matching the insn suffix. */ + { + unsigned int mask, allowed = 0; + const template *t; + + for (t = current_templates->start; t < current_templates->end; ++t) + allowed |= t->operand_types[op]; + switch (guess_suffix) + { + case QWORD_MNEM_SUFFIX: + mask = Imm64 | Imm32S; + break; + case LONG_MNEM_SUFFIX: + mask = Imm32; + break; + case WORD_MNEM_SUFFIX: + mask = Imm16; + break; + case BYTE_MNEM_SUFFIX: + mask = Imm8; + break; + default: + mask = 0; + break; + } + if (mask & allowed) + i.types[op] &= mask; + } + 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) + { + if (i.op[op].disps->X_op == O_constant) + { + offsetT disp = i.op[op].disps->X_add_number; + + if ((i.types[op] & Disp16) + && (disp & ~(offsetT) 0xffff) == 0) + { + /* If this operand is at most 16 bits, convert + to a signed 16 bit number and don't use 64bit + displacement. */ + disp = (((disp & 0xffff) ^ 0x8000) - 0x8000); + i.types[op] &= ~Disp64; + } + if ((i.types[op] & Disp32) + && (disp & ~(((offsetT) 2 << 31) - 1)) == 0) + { + /* If this operand is at most 32 bits, convert + to a signed 32 bit number and don't use 64bit + displacement. */ + disp &= (((offsetT) 2 << 31) - 1); + disp = (disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31); + i.types[op] &= ~Disp64; + } + if (!disp && (i.types[op] & BaseIndex)) + { + i.types[op] &= ~Disp; + i.op[op].disps = 0; + i.disp_operands--; + } + else if (flag_code == CODE_64BIT) + { + if (fits_in_signed_long (disp)) + { + i.types[op] &= ~Disp64; + 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; + } + else if (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL + || i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL) + { + fix_new_exp (frag_now, frag_more (0) - frag_now->fr_literal, 0, + i.op[op].disps, 0, i.reloc[op]); + i.types[op] &= ~Disp; + } + else + /* We only support 64bit displacement on constants. */ + i.types[op] &= ~Disp64; + } +} + +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))) + continue; + + /* In general, don't allow 64-bit operands in 32-bit mode. */ + if (i.suffix == QWORD_MNEM_SUFFIX + && flag_code != CODE_64BIT + && (intel_syntax + ? (!(t->opcode_modifier & IgnoreSize) + && !intel_float_operand (t->name)) + : intel_float_operand (t->name) != 2) + && (!(t->operand_types[0] & (RegMMX | RegXMM)) + || !(t->operand_types[t->operands > 1] & (RegMMX | RegXMM))) + && (t->base_opcode != 0x0fc7 + || t->extension_opcode != 1 /* cmpxchg8b */)) + 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]) + /* monitor in SSE3 is a very special case. The first + register and the second register may have differnet + sizes. */ + || !((t->base_opcode == 0x0f01 + && t->extension_opcode == 0xc8) + || 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 (void) +{ + /* 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 + /* exclude fldenv/frstor/fsave/fstenv */ + && (i.tm.opcode_modifier & No_sSuf)) + { + i.suffix = stackop_size; + } + else if (intel_syntax + && !i.suffix + && ((i.tm.operand_types[0] & JumpAbsolute) + || (i.tm.opcode_modifier & (JumpByte|JumpInterSegment)) + || (i.tm.base_opcode == 0x0f01 /* [ls][gi]dt */ + && i.tm.extension_opcode <= 3))) + { + switch (flag_code) + { + case CODE_64BIT: + if (!(i.tm.opcode_modifier & No_qSuf)) + { + i.suffix = QWORD_MNEM_SUFFIX; + break; + } + case CODE_32BIT: + if (!(i.tm.opcode_modifier & No_lSuf)) + i.suffix = LONG_MNEM_SUFFIX; + break; + case CODE_16BIT: + if (!(i.tm.opcode_modifier & No_wSuf)) + i.suffix = WORD_MNEM_SUFFIX; + break; + } + } + + if (!i.suffix) + { + if (!intel_syntax) + { + if (i.tm.opcode_modifier & W) + { + as_bad (_("no instruction mnemonic suffix given and no register operands; can't size instruction")); + return 0; + } + } + else + { + unsigned int suffixes = ~i.tm.opcode_modifier + & (No_bSuf + | No_wSuf + | No_lSuf + | No_sSuf + | No_xSuf + | No_qSuf); + + if ((i.tm.opcode_modifier & W) + || ((suffixes & (suffixes - 1)) + && !(i.tm.opcode_modifier & (DefaultSize | IgnoreSize)))) + { + as_bad (_("ambiguous operand size for `%s'"), i.tm.name); + return 0; + } + } + } + + /* Change the opcode based on the operand size given by i.suffix; + We don't need to change things for byte insns. */ + + 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.tm.base_opcode == 0x0f01 && i.tm.extension_opcode == 0xc8) + { + /* monitor in SSE3 is a very special case. The default size + of AX is the size of mode. The address size override + prefix will change the size of AX. */ + if (i.op->regs[0].reg_type & + (flag_code == CODE_32BIT ? Reg16 : Reg32)) + if (!add_prefix (ADDR_PREFIX_OPCODE)) + return 0; + } + else if (i.suffix != QWORD_MNEM_SUFFIX + && i.suffix != LONG_DOUBLE_MNEM_SUFFIX + && !(i.tm.opcode_modifier & (IgnoreSize | FloatMF)) + && ((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 (void) +{ + 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) + { + /* 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 | Imm64)) + && 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 | Imm64)) + && 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.tm.cpu_flags & CpuSVME)) + && i.seg[0] && !quiet_warnings) + as_warn (_("segment override on `%s' is ineffectual"), i.tm.name); + + /* 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; + } + if (flag_code != CODE_64BIT && (i.rex & (REX_EXTX | REX_EXTZ))) + { + if (!((i.types[0] | i.types[1]) & Control)) + abort (); + i.rex &= ~(REX_EXTX | REX_EXTZ); + add_prefix (LOCK_PREFIX_OPCODE); + } + } + 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_64BIT) + { + /* 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] = ((i.prefix[ADDR_PREFIX] == 0) ? Disp32S : Disp32); + } + else if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0)) + { + i.rm.regmem = NO_BASE_REGISTER_16; + i.types[op] = Disp16; + } + else + { + i.rm.regmem = NO_BASE_REGISTER; + i.types[op] = Disp32; + } + } + 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; + if (! i.disp_operands) + fake_zero_displacement = 1; + } + 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)) + i.types[op] = (i.types[op] & Disp8) | (i.prefix[ADDR_PREFIX] == 0 ? Disp32S : Disp32); + + 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; + } + + if (i.disp_operands + && (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL + || i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL)) + i.rm.mode = 0; + else + 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; + unsigned int prefix; + + /* All opcodes on i386 have either 1 or 2 bytes. Merom New + Instructions have 3 bytes. We may use one more higher byte + to specify a prefix the instruction requires. */ + if ((i.tm.cpu_flags & CpuMNI) != 0) + { + if (i.tm.base_opcode & 0xff000000) + { + prefix = (i.tm.base_opcode >> 24) & 0xff; + goto check_prefix; + } + } + else if ((i.tm.base_opcode & 0xff0000) != 0) + { + prefix = (i.tm.base_opcode >> 16) & 0xff; + if ((i.tm.cpu_flags & CpuPadLock) != 0) + { +check_prefix: + if (prefix != REPE_PREFIX_OPCODE + || i.prefix[LOCKREP_PREFIX] != REPE_PREFIX_OPCODE) + add_prefix (prefix); + } + else + add_prefix (prefix); + } + + /* 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 + { + if ((i.tm.cpu_flags & CpuMNI) != 0) + { + p = frag_more (3); + *p++ = (i.tm.base_opcode >> 16) & 0xff; + } + 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 + { + enum bfd_reloc_code_real 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]); + if (GOT_symbol + && GOT_symbol == i.op[n].disps->X_add_symbol + && (((reloc_type == BFD_RELOC_32 + || reloc_type == BFD_RELOC_X86_64_32S + || (reloc_type == BFD_RELOC_64 + && object_64bit)) + && (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)))) + || reloc_type == BFD_RELOC_32_PCREL)) + { + 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; + } + + if (!object_64bit) + { + reloc_type = BFD_RELOC_386_GOTPC; + i.op[n].imms->X_add_number += add; + } + else if (reloc_type == BFD_RELOC_64) + reloc_type = BFD_RELOC_X86_64_GOTPC64; + else + /* Don't do the adjustment for x86-64, as there + the pcrel addressing is relative to the _next_ + insn, and that is taken care of in other code. */ + reloc_type = BFD_RELOC_X86_64_GOTPC32; + } + 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 ... */ + enum bfd_reloc_code_real reloc_type; + int size = 4; + int sign = 0; + + if ((i.types[n] & (Imm32S)) + && (i.suffix == QWORD_MNEM_SUFFIX + || (!i.suffix && (i.tm.opcode_modifier & No_lSuf)))) + 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]); + + /* 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 + || reloc_type == BFD_RELOC_X86_64_32S + || reloc_type == BFD_RELOC_64) + && 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; + } + + if (!object_64bit) + reloc_type = BFD_RELOC_386_GOTPC; + else if (size == 4) + reloc_type = BFD_RELOC_X86_64_GOTPC32; + else if (size == 8) + reloc_type = BFD_RELOC_X86_64_GOTPC64; + i.op[n].imms->X_add_number += add; + } + fix_new_exp (frag_now, p - frag_now->fr_literal, size, + i.op[n].imms, 0, reloc_type); + } + } + } +} + +/* 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 enum bfd_reloc_code_real got_reloc = NO_RELOC; +static int cons_sign = -1; + +void +x86_cons_fix_new (fragS *frag, + unsigned int off, + unsigned int len, + expressionS *exp) +{ + enum bfd_reloc_code_real r = reloc (len, 0, cons_sign, got_reloc); + + got_reloc = NO_RELOC; + +#ifdef TE_PE + if (exp->X_op == O_secrel) + { + exp->X_op = O_symbol; + r = BFD_RELOC_32_SECREL; + } +#endif + + fix_new_exp (frag, off, len, exp, 0, r); +} + +#if (!defined (OBJ_ELF) && !defined (OBJ_MAYBE_ELF)) || defined (LEX_AT) +# define lex_got(reloc, adjust, types) NULL +#else +/* 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 (enum bfd_reloc_code_real *reloc, + int *adjust, + unsigned int *types) +{ + /* Some of the relocations depend on the size of what field is to + be relocated. But in our callers i386_immediate and i386_displacement + we don't yet know the operand size (this will be set by insn + matching). Hence we record the word32 relocation here, + and adjust the reloc according to the real size in reloc(). */ + static const struct { + const char *str; + const enum bfd_reloc_code_real rel[2]; + const unsigned int types64; + } gotrel[] = { + { "PLTOFF", { 0, BFD_RELOC_X86_64_PLTOFF64 }, Imm64 }, + { "PLT", { BFD_RELOC_386_PLT32, BFD_RELOC_X86_64_PLT32 }, Imm32|Imm32S|Disp32 }, + { "GOTPLT", { 0, BFD_RELOC_X86_64_GOTPLT64 }, Imm64|Disp64 }, + { "GOTOFF", { BFD_RELOC_386_GOTOFF, BFD_RELOC_X86_64_GOTOFF64 }, Imm64|Disp64 }, + { "GOTPCREL", { 0, BFD_RELOC_X86_64_GOTPCREL }, Imm32|Imm32S|Disp32 }, + { "TLSGD", { BFD_RELOC_386_TLS_GD, BFD_RELOC_X86_64_TLSGD }, Imm32|Imm32S|Disp32 }, + { "TLSLDM", { BFD_RELOC_386_TLS_LDM, 0 }, 0 }, + { "TLSLD", { 0, BFD_RELOC_X86_64_TLSLD }, Imm32|Imm32S|Disp32 }, + { "GOTTPOFF", { BFD_RELOC_386_TLS_IE_32, BFD_RELOC_X86_64_GOTTPOFF }, Imm32|Imm32S|Disp32 }, + { "TPOFF", { BFD_RELOC_386_TLS_LE_32, BFD_RELOC_X86_64_TPOFF32 }, Imm32|Imm32S|Imm64|Disp32|Disp64 }, + { "NTPOFF", { BFD_RELOC_386_TLS_LE, 0 }, 0 }, + { "DTPOFF", { BFD_RELOC_386_TLS_LDO_32, BFD_RELOC_X86_64_DTPOFF32 }, Imm32|Imm32S|Imm64|Disp32|Disp64 }, + { "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE, 0 }, 0 }, + { "INDNTPOFF",{ BFD_RELOC_386_TLS_IE, 0 }, 0 }, + { "GOT", { BFD_RELOC_386_GOT32, BFD_RELOC_X86_64_GOT32 }, Imm32|Imm32S|Disp32|Imm64 }, + { "TLSDESC", { BFD_RELOC_386_TLS_GOTDESC, BFD_RELOC_X86_64_GOTPC32_TLSDESC }, Imm32|Imm32S|Disp32 }, + { "TLSCALL", { BFD_RELOC_386_TLS_DESC_CALL, BFD_RELOC_X86_64_TLSDESC_CALL }, Imm32|Imm32S|Disp32 } + }; + char *cp; + unsigned int j; + + if (!IS_ELF) + return NULL; + + 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[object_64bit] != 0) + { + int first, second; + char *tmpbuf, *past_reloc; + + *reloc = gotrel[j].rel[object_64bit]; + if (adjust) + *adjust = len; + + if (types) + { + if (flag_code != CODE_64BIT) + *types = Imm32|Disp32; + else + *types = gotrel[j].types64; + } + + 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 with %d-bit output format"), + gotrel[j].str, 1 << (5 + object_64bit)); + return NULL; + } + } + + /* Might be a symbol version string. Don't as_bad here. */ + return NULL; +} + +void +x86_cons (exp, size) + expressionS *exp; + int size; +{ + if (size == 4 || (object_64bit && size == 8)) + { + /* 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, NULL); + 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 void signed_cons (int size) +{ + if (flag_code == CODE_64BIT) + cons_sign = 1; + cons (size); + cons_sign = -1; +} + +#ifdef TE_PE +static void +pe_directive_secrel (dummy) + int dummy ATTRIBUTE_UNUSED; +{ + expressionS exp; + + do + { + expression (&exp); + if (exp.X_op == O_symbol) + exp.X_op = O_secrel; + + emit_expr (&exp, 4); + } + while (*input_line_pointer++ == ','); + + input_line_pointer--; + demand_empty_rest_of_line (); +} +#endif + +static int i386_immediate PARAMS ((char *)); + +static int +i386_immediate (imm_start) + char *imm_start; +{ + char *save_input_line_pointer; + char *gotfree_input_line; + segT exp_seg = 0; + expressionS *exp; + unsigned int types = ~0U; + + 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; + + gotfree_input_line = lex_got (&i.reloc[this_operand], NULL, &types); + if (gotfree_input_line) + input_line_pointer = gotfree_input_line; + + 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; + if (gotfree_input_line) + free (gotfree_input_line); + + 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 (OUTPUT_FLAVOR == bfd_target_aout_flavour + && exp_seg != absolute_section + && exp_seg != text_section + && exp_seg != data_section + && exp_seg != bss_section + && exp_seg != undefined_section + && !bfd_is_com_section (exp_seg)) + { + as_bad (_("unimplemented segment %s in operand"), exp_seg->name); + 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; + i.types[this_operand] &= types; + } + + 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 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: + { + char sep = *input_line_pointer; + + *input_line_pointer = '\0'; + as_bad (_("expecting scale factor of 1, 2, 4, or 8: got `%s'"), + scale); + *input_line_pointer = sep; + 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; + char *gotfree_input_line; + int bigdisp, override; + unsigned int types = Disp; + + if ((i.types[this_operand] & JumpAbsolute) + || !(current_templates->start->opcode_modifier & (Jump | JumpDword))) + { + bigdisp = Disp32; + override = (i.prefix[ADDR_PREFIX] != 0); + } + else + { + /* For PC-relative branches, the width of the displacement + is dependent upon data size, not address size. */ + bigdisp = 0; + override = (i.prefix[DATA_PREFIX] != 0); + } + if (flag_code == CODE_64BIT) + { + if (!bigdisp) + bigdisp = (override || i.suffix == WORD_MNEM_SUFFIX) + ? Disp16 + : Disp32S | Disp32; + else if (!override) + bigdisp = Disp64 | Disp32S | Disp32; + } + else + { + if (!bigdisp) + { + if (!override) + override = (i.suffix == (flag_code != CODE_16BIT + ? WORD_MNEM_SUFFIX + : LONG_MNEM_SUFFIX)); + bigdisp = Disp32; + } + if ((flag_code == CODE_16BIT) ^ override) + 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 + gotfree_input_line = lex_got (&i.reloc[this_operand], NULL, &types); + if (gotfree_input_line) + input_line_pointer = gotfree_input_line; + + 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; + if (gotfree_input_line) + free (gotfree_input_line); + + /* 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 + || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64) + { + 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 if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64) + i.reloc[this_operand] = BFD_RELOC_64; + else + i.reloc[this_operand] = BFD_RELOC_32; + } + + 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 + && OUTPUT_FLAVOR == bfd_target_aout_flavour + && exp_seg != absolute_section + && exp_seg != text_section + && exp_seg != data_section + && exp_seg != bss_section + && exp_seg != undefined_section + && !bfd_is_com_section (exp_seg)) + { + as_bad (_("unimplemented segment %s in operand"), exp_seg->name); + return 0; + } +#endif + + if (!(i.types[this_operand] & ~Disp)) + i.types[this_operand] &= types; + + 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 ((current_templates->start->cpu_flags & CpuSVME) + && current_templates->end[-1].operand_types[0] == AnyMem) + { + /* Memory operands of SVME insns are special in that they only allow + rAX as their memory address and ignore any segment override. */ + unsigned RegXX; + + /* SKINIT is even more restrictive: it always requires EAX. */ + if (strcmp (current_templates->start->name, "skinit") == 0) + RegXX = Reg32; + else if (flag_code == CODE_64BIT) + RegXX = i.prefix[ADDR_PREFIX] == 0 ? Reg64 : Reg32; + else + RegXX = (flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0) + ? Reg16 + : Reg32; + if (!i.base_reg + || !(i.base_reg->reg_type & Acc) + || !(i.base_reg->reg_type & RegXX) + || i.index_reg + || (i.types[0] & Disp)) + ok = 0; + } + else if (flag_code == CODE_64BIT) + { + unsigned RegXX = (i.prefix[ADDR_PREFIX] == 0 ? Reg64 : Reg32); + + if ((i.base_reg + && ((i.base_reg->reg_type & RegXX) == 0) + && (i.base_reg->reg_type != BaseIndex + || i.index_reg)) + || (i.index_reg + && ((i.index_reg->reg_type & (RegXX | BaseIndex)) + != (RegXX | 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 (i.prefix[ADDR_PREFIX] == 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 (flag_code != CODE_64BIT && (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 ok; +} + +/* 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 ((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 == ',' + || ((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 ((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) + || (IS_ELF + && (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; + enum bfd_reloc_code_real 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". */ + +void +md_convert_frag (abfd, sec, fragP) + bfd *abfd ATTRIBUTE_UNUSED; + segT sec ATTRIBUTE_UNUSED; + fragS *fragP; +{ + 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; + } + } + + /* If size if less then four we are sure that the operand fits, + but if it's 4, then it could be that the displacement is larger + then -/+ 2GB. */ + if (DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype) == 4 + && object_64bit + && ((addressT) (displacement_from_opcode_start - extension + + ((addressT) 1 << 31)) + > (((addressT) 2 << 31) - 1))) + { + as_bad_where (fragP->fr_file, fragP->fr_line, + _("jump target out of range")); + /* Make us emit 0. */ + displacement_from_opcode_start = extension; + } + /* 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; + +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_fix (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 (TE_Mach) + if (fixP->fx_pcrel) + { + switch (fixP->fx_r_type) + { + default: + break; + + case BFD_RELOC_64: + fixP->fx_r_type = BFD_RELOC_64_PCREL; + break; + case BFD_RELOC_32: + case BFD_RELOC_X86_64_32S: + 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_64_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 (IS_ELF +#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 (IS_ELF) + { + 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 + || S_IS_WEAK (fixP->fx_addsy)) + value += md_pcrel_from (fixP); +#endif + } + + /* Fix a few things - the dynamic linker expects certain values here, + and we must not disappoint it. */ +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (IS_ELF && 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_386_TLS_GOTDESC: + case BFD_RELOC_X86_64_TLSGD: + case BFD_RELOC_X86_64_TLSLD: + case BFD_RELOC_X86_64_GOTTPOFF: + case BFD_RELOC_X86_64_GOTPC32_TLSDESC: + 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_DTPOFF64: + case BFD_RELOC_X86_64_TPOFF32: + case BFD_RELOC_X86_64_TPOFF64: + S_SET_THREAD_LOCAL (fixP->fx_addsy); + break; + + case BFD_RELOC_386_TLS_DESC_CALL: + case BFD_RELOC_X86_64_TLSDESC_CALL: + value = 0; /* Fully resolved at runtime. No addend. */ + S_SET_THREAD_LOCAL (fixP->fx_addsy); + fixP->fx_done = 0; + return; + + 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 (TE_Mach) */ + + /* Are we finished with this relocation now? */ + if (fixP->fx_addsy == NULL) + fixP->fx_done = 1; + else if (use_rela_relocations) + { + fixP->fx_no_overflow = 1; + /* Remember value for tc_gen_reloc. */ + fixP->fx_addnumber = value; + value = 0; + } + + 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; +} + +static 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_real_register (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)) | (r->reg_type & Reg64)) != 0 + && (r->reg_type != Control || !(cpu_arch_flags & CpuSledgehammer)) + && flag_code != CODE_64BIT) + return (const reg_entry *) NULL; + + return r; +} + +/* REG_STRING starts *before* REGISTER_PREFIX. */ + +static const reg_entry * +parse_register (char *reg_string, char **end_op) +{ + const reg_entry *r; + + if (*reg_string == REGISTER_PREFIX || allow_naked_reg) + r = parse_real_register (reg_string, end_op); + else + r = NULL; + if (!r) + { + char *save = input_line_pointer; + char c; + symbolS *symbolP; + + input_line_pointer = reg_string; + c = get_symbol_end (); + symbolP = symbol_find (reg_string); + if (symbolP && S_GET_SEGMENT (symbolP) == reg_section) + { + const expressionS *e = symbol_get_value_expression (symbolP); + + know (e->X_op == O_register); + know (e->X_add_number >= 0 && (valueT) e->X_add_number < ARRAY_SIZE (i386_regtab)); + r = i386_regtab + e->X_add_number; + *end_op = input_line_pointer; + } + *input_line_pointer = c; + input_line_pointer = save; + } + return r; +} + +int +i386_parse_name (char *name, expressionS *e, char *nextcharP) +{ + const reg_entry *r; + char *end = input_line_pointer; + + *end = *nextcharP; + r = parse_register (name, &input_line_pointer); + if (r && end <= input_line_pointer) + { + *nextcharP = *input_line_pointer; + *input_line_pointer = 0; + e->X_op = O_register; + e->X_add_number = r - i386_regtab; + return 1; + } + input_line_pointer = end; + *end = 0; + return 0; +} + +void +md_operand (expressionS *e) +{ + if (*input_line_pointer == REGISTER_PREFIX) + { + char *end; + const reg_entry *r = parse_real_register (input_line_pointer, &end); + + if (r) + { + e->X_op = O_register; + e->X_add_number = r - i386_regtab; + input_line_pointer = end; + } + } +} + + +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) +const char *md_shortopts = "kVQ:sqn"; +#else +const char *md_shortopts = "qn"; +#endif + +#define OPTION_32 (OPTION_MD_BASE + 0) +#define OPTION_64 (OPTION_MD_BASE + 1) +#define OPTION_DIVIDE (OPTION_MD_BASE + 2) + +struct option md_longopts[] = { + {"32", no_argument, NULL, OPTION_32}, +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + {"64", no_argument, NULL, OPTION_64}, +#endif + {"divide", no_argument, NULL, OPTION_DIVIDE}, + {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 'n': + optimize_align_code = 0; + break; + + 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; + + case OPTION_DIVIDE: +#ifdef SVR4_COMMENT_CHARS + { + char *n, *t; + const char *s; + + n = (char *) xmalloc (strlen (i386_comment_chars) + 1); + t = n; + for (s = i386_comment_chars; *s != '\0'; s++) + if (*s != '/') + *t++ = *s; + *t = '\0'; + i386_comment_chars = n; + } +#endif + 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")); +#endif + fprintf (stream, _("\ + -n Do not optimize code alignment\n\ + -q quieten some warnings\n")); +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + fprintf (stream, _("\ + -s ignored\n")); +#endif +#ifdef SVR4_COMMENT_CHARS + fprintf (stream, _("\ + --divide do not treat `/' as a comment character\n")); +#else + fprintf (stream, _("\ + --divide ignored\n")); +#endif +} + +#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) + { + object_64bit = 1; + 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 (IS_ELF && 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 + +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; +{ +#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 + + 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; + +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (IS_ELF) + obj_elf_section_change_hook (); +#endif + temp = get_absolute_expression (); + subseg_set (bss_section, (subsegT) temp); + demand_empty_rest_of_line (); +} + +#endif + +void +i386_validate_fix (fixp) + fixS *fixp; +{ + if (fixp->fx_subsy && fixp->fx_subsy == GOT_symbol) + { + if (fixp->fx_r_type == BFD_RELOC_32_PCREL) + { + if (!object_64bit) + abort (); + fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL; + } + else + { + if (!object_64bit) + fixp->fx_r_type = BFD_RELOC_386_GOTOFF; + else + fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64; + } + 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_386_TLS_GOTDESC: + case BFD_RELOC_386_TLS_DESC_CALL: + case BFD_RELOC_X86_64_TLSGD: + case BFD_RELOC_X86_64_TLSLD: + case BFD_RELOC_X86_64_DTPOFF32: + case BFD_RELOC_X86_64_DTPOFF64: + case BFD_RELOC_X86_64_GOTTPOFF: + case BFD_RELOC_X86_64_TPOFF32: + case BFD_RELOC_X86_64_TPOFF64: + case BFD_RELOC_X86_64_GOTOFF64: + case BFD_RELOC_X86_64_GOTPC32: + case BFD_RELOC_X86_64_GOT64: + case BFD_RELOC_X86_64_GOTPCREL64: + case BFD_RELOC_X86_64_GOTPC64: + case BFD_RELOC_X86_64_GOTPLT64: + case BFD_RELOC_X86_64_PLTOFF64: + case BFD_RELOC_X86_64_GOTPC32_TLSDESC: + case BFD_RELOC_X86_64_TLSDESC_CALL: + case BFD_RELOC_RVA: + case BFD_RELOC_VTABLE_ENTRY: + case BFD_RELOC_VTABLE_INHERIT: +#ifdef TE_PE + case BFD_RELOC_32_SECREL: +#endif + code = fixp->fx_r_type; + break; + case BFD_RELOC_X86_64_32S: + if (!fixp->fx_pcrel) + { + /* Don't turn BFD_RELOC_X86_64_32S into BFD_RELOC_32. */ + 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; +#ifdef BFD64 + case 8: code = BFD_RELOC_64_PCREL; break; +#endif + } + } + 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 + || code == BFD_RELOC_32_PCREL + || code == BFD_RELOC_X86_64_32S) + && GOT_symbol + && fixp->fx_addsy == GOT_symbol) + { + if (!object_64bit) + code = BFD_RELOC_386_GOTPC; + else + code = BFD_RELOC_X86_64_GOTPC32; + } + if ((code == BFD_RELOC_64 || code == BFD_RELOC_64_PCREL) + && GOT_symbol + && fixp->fx_addsy == GOT_symbol) + { + code = BFD_RELOC_X86_64_GOTPC64; + } + + 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: + case BFD_RELOC_X86_64_GOTPC32_TLSDESC: + case BFD_RELOC_X86_64_TLSDESC_CALL: + 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; +} + + +/* 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] + + binOp & | AND | \| | OR | ^ | XOR + + byteRegister AL | AH | BL | BH | CL | CH | DL | DH + + constant digits [[ radixOverride ]] + + dataType BYTE | WORD | DWORD | FWORD | QWORD | TBYTE | OWORD | XMMWORD + + digits decdigit + | digits decdigit + | digits hexdigit + + decdigit [0-9] + + e04 e04 addOp e05 + | e05 + + e05 e05 binOp e06 + | e06 + + e06 e06 mulOp e09 + | e09 + + e09 OFFSET e10 + | SHORT e10 + | + e10 + | - e10 + | ~ e10 + | NOT e10 + | e09 PTR e10 + | e09 : e10 + | e10 + + e10 e10 [ expr ] + | e11 + + e11 ( expr ) + | [ expr ] + | constant + | dataType + | id + | $ + | register + + => expr expr cmpOp e04 + | e04 + + 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 | << | SHL | >> | SHR + + quote " | ' + + register specialRegister + | gpRegister + | byteRegister + + segmentRegister CS | DS | ES | FS | GS | SS + + specialRegister CR0 | CR2 | CR3 | CR4 + | 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 e04 expr' + + expr' cmpOp e04 expr' + | Empty + + e04 e05 e04' + + e04' addOp e05 e04' + | Empty + + e05 e06 e05' + + e05' binOp e06 e05' + | Empty + + e06 e09 e06' + + e06' mulOp e09 e06' + | Empty + + e09 OFFSET e10 e09' + | SHORT e10' + | + e10' + | - e10' + | ~ e10' + | NOT e10' + | e10 e09' + + e09' PTR e10 e09' + | : e10 e09' + | Empty + + e10 e11 e10' + + e10' [ expr ] e10' + | Empty + + e11 ( expr ) + | [ expr ] + | BYTE + | WORD + | DWORD + | FWORD + | QWORD + | TBYTE + | OWORD + | XMMWORD + | . + | $ + | 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. */ + int in_offset; /* >=1 if parsing operand of offset. */ + int in_bracket; /* >=1 if parsing operand in brackets. */ + const reg_entry *reg; /* Last register reference found. */ + char *disp; /* Displacement string being built. */ + char *next_operand; /* Resume point when splitting operands. */ + }; + +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_FWORD 6 +#define T_QWORD 7 +#define T_TBYTE 8 +#define T_XMMWORD 9 +#undef T_SHORT +#define T_SHORT 10 +#define T_OFFSET 11 +#define T_PTR 12 +#define T_ID 13 +#define T_SHL 14 +#define T_SHR 15 + +/* 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_e04 PARAMS ((void)); +static int intel_e05 PARAMS ((void)); +static int intel_e06 PARAMS ((void)); +static int intel_e09 PARAMS ((void)); +static int intel_bracket_expr PARAMS ((void)); +static int intel_e10 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; + + p = intel_parser.op_string = xstrdup (operand_string); + intel_parser.disp = (char *) xmalloc (strlen (operand_string) + 1); + + for (;;) + { + /* 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. */ + intel_parser.got_a_float = got_a_float; + intel_parser.op_modifier = 0; + intel_parser.is_mem = 0; + intel_parser.in_offset = 0; + intel_parser.in_bracket = 0; + intel_parser.reg = NULL; + intel_parser.disp[0] = '\0'; + intel_parser.next_operand = NULL; + + /* Read the first token and start the parser. */ + intel_get_token (); + ret = intel_expr (); + + if (!ret) + break; + + if (cur_token.code != T_NIL) + { + as_bad (_("invalid operand for '%s' ('%s' unexpected)"), + current_templates->start->name, cur_token.str); + ret = 0; + } + /* If we found a memory reference, hand it over to i386_displacement + to fill in the rest of the operand fields. */ + else 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++; + + if (!quiet_warnings && intel_parser.is_mem < 0) + /* See the comments in intel_bracket_expr. */ + as_warn (_("Treating `%s' as memory reference"), operand_string); + + /* Add the displacement expression. */ + if (*s != '\0') + ret = i386_displacement (s, s + strlen (s)); + if (ret) + { + /* Swap base and index in 16-bit memory operands like + [si+bx]. Since i386_index_check is also used in AT&T + mode we have to do that here. */ + if (i.base_reg + && i.index_reg + && (i.base_reg->reg_type & Reg16) + && (i.index_reg->reg_type & Reg16) + && i.base_reg->reg_num >= 6 + && i.index_reg->reg_num < 6) + { + const reg_entry *base = i.index_reg; + + i.index_reg = i.base_reg; + i.base_reg = base; + } + ret = i386_index_check (operand_string); + } + } + } + + /* Constant and OFFSET expressions are handled by i386_immediate. */ + else if ((intel_parser.op_modifier & (1 << T_OFFSET)) + || intel_parser.reg == NULL) + ret = i386_immediate (intel_parser.disp); + + if (intel_parser.next_operand && this_operand >= MAX_OPERANDS - 1) + ret = 0; + if (!ret || !intel_parser.next_operand) + break; + intel_parser.op_string = intel_parser.next_operand; + this_operand = i.operands++; + } + + free (p); + free (intel_parser.disp); + + return ret; +} + +#define NUM_ADDRESS_REGS (!!i.base_reg + !!i.index_reg) + +/* expr e04 expr' + + expr' cmpOp e04 expr' + | Empty */ +static int +intel_expr () +{ + /* XXX Implement the comparison operators. */ + return intel_e04 (); +} + +/* e04 e05 e04' + + e04' addOp e05 e04' + | Empty */ +static int +intel_e04 () +{ + int nregs = -1; + + for (;;) + { + if (!intel_e05()) + return 0; + + if (nregs >= 0 && NUM_ADDRESS_REGS > nregs) + i.base_reg = i386_regtab + REGNAM_AL; /* al is invalid as base */ + + if (cur_token.code == '+') + nregs = -1; + else if (cur_token.code == '-') + nregs = NUM_ADDRESS_REGS; + else + return 1; + + strcat (intel_parser.disp, cur_token.str); + intel_match_token (cur_token.code); + } +} + +/* e05 e06 e05' + + e05' binOp e06 e05' + | Empty */ +static int +intel_e05 () +{ + int nregs = ~NUM_ADDRESS_REGS; + + for (;;) + { + if (!intel_e06()) + return 0; + + if (cur_token.code == '&' || cur_token.code == '|' || cur_token.code == '^') + { + char str[2]; + + str[0] = cur_token.code; + str[1] = 0; + strcat (intel_parser.disp, str); + } + else + break; + + intel_match_token (cur_token.code); + + if (nregs < 0) + nregs = ~nregs; + } + if (nregs >= 0 && NUM_ADDRESS_REGS > nregs) + i.base_reg = i386_regtab + REGNAM_AL + 1; /* cl is invalid as base */ + return 1; +} + +/* e06 e09 e06' + + e06' mulOp e09 e06' + | Empty */ +static int +intel_e06 () +{ + int nregs = ~NUM_ADDRESS_REGS; + + for (;;) + { + if (!intel_e09()) + return 0; + + if (cur_token.code == '*' || cur_token.code == '/' || cur_token.code == '%') + { + char str[2]; + + str[0] = cur_token.code; + str[1] = 0; + strcat (intel_parser.disp, str); + } + else if (cur_token.code == T_SHL) + strcat (intel_parser.disp, "<<"); + else if (cur_token.code == T_SHR) + strcat (intel_parser.disp, ">>"); + else + break; + + intel_match_token (cur_token.code); + + if (nregs < 0) + nregs = ~nregs; + } + if (nregs >= 0 && NUM_ADDRESS_REGS > nregs) + i.base_reg = i386_regtab + REGNAM_AL + 2; /* dl is invalid as base */ + return 1; +} + +/* e09 OFFSET e09 + | SHORT e09 + | + e09 + | - e09 + | ~ e09 + | NOT e09 + | e10 e09' + + e09' PTR e10 e09' + | : e10 e09' + | Empty */ +static int +intel_e09 () +{ + int nregs = ~NUM_ADDRESS_REGS; + int in_offset = 0; + + for (;;) + { + /* Don't consume constants here. */ + if (cur_token.code == '+' || cur_token.code == '-') + { + /* Need to look one token ahead - if the next token + is a constant, the current token is its sign. */ + int next_code; + + intel_match_token (cur_token.code); + next_code = cur_token.code; + intel_putback_token (); + if (next_code == T_CONST) + break; + } + + /* e09 OFFSET e09 */ + if (cur_token.code == T_OFFSET) + { + if (!in_offset++) + ++intel_parser.in_offset; + } + + /* e09 SHORT e09 */ + else if (cur_token.code == T_SHORT) + intel_parser.op_modifier |= 1 << T_SHORT; + + /* e09 + e09 */ + else if (cur_token.code == '+') + strcat (intel_parser.disp, "+"); + + /* e09 - e09 + | ~ e09 + | NOT e09 */ + else if (cur_token.code == '-' || cur_token.code == '~') + { + char str[2]; + + if (nregs < 0) + nregs = ~nregs; + str[0] = cur_token.code; + str[1] = 0; + strcat (intel_parser.disp, str); + } + + /* e09 e10 e09' */ + else + break; + + intel_match_token (cur_token.code); + } + + for (;;) + { + if (!intel_e10 ()) + return 0; + + /* e09' PTR e10 e09' */ + if (cur_token.code == T_PTR) + { + char suffix; + + if (prev_token.code == T_BYTE) + suffix = BYTE_MNEM_SUFFIX; + + else if (prev_token.code == T_WORD) + { + if (current_templates->start->name[0] == 'l' + && current_templates->start->name[2] == 's' + && current_templates->start->name[3] == 0) + suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */ + else if (intel_parser.got_a_float == 2) /* "fi..." */ + suffix = SHORT_MNEM_SUFFIX; + else + suffix = WORD_MNEM_SUFFIX; + } + + else if (prev_token.code == T_DWORD) + { + if (current_templates->start->name[0] == 'l' + && current_templates->start->name[2] == 's' + && current_templates->start->name[3] == 0) + suffix = WORD_MNEM_SUFFIX; + else if (flag_code == CODE_16BIT + && (current_templates->start->opcode_modifier + & (Jump | JumpDword))) + suffix = LONG_DOUBLE_MNEM_SUFFIX; + else if (intel_parser.got_a_float == 1) /* "f..." */ + suffix = SHORT_MNEM_SUFFIX; + else + suffix = LONG_MNEM_SUFFIX; + } + + else if (prev_token.code == T_FWORD) + { + if (current_templates->start->name[0] == 'l' + && current_templates->start->name[2] == 's' + && current_templates->start->name[3] == 0) + suffix = LONG_MNEM_SUFFIX; + else if (!intel_parser.got_a_float) + { + if (flag_code == CODE_16BIT) + add_prefix (DATA_PREFIX_OPCODE); + suffix = LONG_DOUBLE_MNEM_SUFFIX; + } + else + suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */ + } + + else if (prev_token.code == T_QWORD) + { + if (intel_parser.got_a_float == 1) /* "f..." */ + suffix = LONG_MNEM_SUFFIX; + else + suffix = QWORD_MNEM_SUFFIX; + } + + else if (prev_token.code == T_TBYTE) + { + if (intel_parser.got_a_float == 1) + suffix = LONG_DOUBLE_MNEM_SUFFIX; + else + suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */ + } + + else if (prev_token.code == T_XMMWORD) + { + /* XXX ignored for now, but accepted since gcc uses it */ + suffix = 0; + } + + else + { + as_bad (_("Unknown operand modifier `%s'"), prev_token.str); + return 0; + } + + /* Operands for jump/call using 'ptr' notation denote absolute + addresses. */ + if (current_templates->start->opcode_modifier & (Jump | JumpDword)) + i.types[this_operand] |= JumpAbsolute; + + if (current_templates->start->base_opcode == 0x8d /* lea */) + ; + else if (!i.suffix) + i.suffix = suffix; + else if (i.suffix != suffix) + { + as_bad (_("Conflicting operand modifiers")); + return 0; + } + + } + + /* e09' : e10 e09' */ + else if (cur_token.code == ':') + { + if (prev_token.code != T_REG) + { + /* While {call,jmp} SSSS:OOOO is MASM syntax only when SSSS is a + segment/group identifier (which we don't have), using comma + as the operand separator there is even less consistent, since + there all branches only have a single operand. */ + if (this_operand != 0 + || intel_parser.in_offset + || intel_parser.in_bracket + || (!(current_templates->start->opcode_modifier + & (Jump|JumpDword|JumpInterSegment)) + && !(current_templates->start->operand_types[0] + & JumpAbsolute))) + return intel_match_token (T_NIL); + /* Remember the start of the 2nd operand and terminate 1st + operand here. + XXX This isn't right, yet (when SSSS:OOOO is right operand of + another expression), but it gets at least the simplest case + (a plain number or symbol on the left side) right. */ + intel_parser.next_operand = intel_parser.op_string; + *--intel_parser.op_string = '\0'; + return intel_match_token (':'); + } + } + + /* e09' Empty */ + else + break; + + intel_match_token (cur_token.code); + + } + + if (in_offset) + { + --intel_parser.in_offset; + if (nregs < 0) + nregs = ~nregs; + if (NUM_ADDRESS_REGS > nregs) + { + as_bad (_("Invalid operand to `OFFSET'")); + return 0; + } + intel_parser.op_modifier |= 1 << T_OFFSET; + } + + if (nregs >= 0 && NUM_ADDRESS_REGS > nregs) + i.base_reg = i386_regtab + REGNAM_AL + 3; /* bl is invalid as base */ + return 1; +} + +static int +intel_bracket_expr () +{ + int was_offset = intel_parser.op_modifier & (1 << T_OFFSET); + const char *start = intel_parser.op_string; + int len; + + if (i.op[this_operand].regs) + return intel_match_token (T_NIL); + + 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.in_offset) + { + ++intel_parser.in_bracket; + + /* Operands for jump/call inside brackets denote absolute addresses. */ + if (current_templates->start->opcode_modifier & (Jump | JumpDword)) + i.types[this_operand] |= JumpAbsolute; + + /* Unfortunately gas always diverged from MASM in a respect that can't + be easily fixed without risking to break code sequences likely to be + encountered (the testsuite even check for this): MASM doesn't consider + an expression inside brackets unconditionally as a memory reference. + When that is e.g. a constant, an offset expression, or the sum of the + two, this is still taken as a constant load. gas, however, always + treated these as memory references. As a compromise, we'll try to make + offset expressions inside brackets work the MASM way (since that's + less likely to be found in real world code), but make constants alone + continue to work the traditional gas way. In either case, issue a + warning. */ + intel_parser.op_modifier &= ~was_offset; + } + 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 () + && (len = intel_parser.op_string - start - 1, + intel_match_token (']'))) + { + /* Preserve brackets when the operand is an offset expression. */ + if (intel_parser.in_offset) + strcat (intel_parser.disp, "]"); + else + { + --intel_parser.in_bracket; + if (i.base_reg || i.index_reg) + intel_parser.is_mem = 1; + if (!intel_parser.is_mem) + { + if (!(intel_parser.op_modifier & (1 << T_OFFSET))) + /* Defer the warning until all of the operand was parsed. */ + intel_parser.is_mem = -1; + else if (!quiet_warnings) + as_warn (_("`[%.*s]' taken to mean just `%.*s'"), len, start, len, start); + } + } + intel_parser.op_modifier |= was_offset; + + return 1; + } + return 0; +} + +/* e10 e11 e10' + + e10' [ expr ] e10' + | Empty */ +static int +intel_e10 () +{ + if (!intel_e11 ()) + return 0; + + while (cur_token.code == '[') + { + if (!intel_bracket_expr ()) + return 0; + } + + return 1; +} + +/* e11 ( expr ) + | [ expr ] + | BYTE + | WORD + | DWORD + | FWORD + | QWORD + | TBYTE + | OWORD + | XMMWORD + | $ + | . + | register + | id + | constant */ +static int +intel_e11 () +{ + switch (cur_token.code) + { + /* e11 ( expr ) */ + case '(': + intel_match_token ('('); + strcat (intel_parser.disp, "("); + + if (intel_expr () && intel_match_token (')')) + { + strcat (intel_parser.disp, ")"); + return 1; + } + return 0; + + /* e11 [ expr ] */ + case '[': + return intel_bracket_expr (); + + /* e11 $ + | . */ + case '.': + 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.in_offset) + intel_parser.is_mem = 1; + + return 1; + + /* e11 register */ + case 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))) + { + as_bad (_("`%s' is not a valid segment register"), reg->reg_name); + return 0; + } + else if (i.seg[i.mem_operands]) + as_warn (_("Extra segment override ignored")); + else + { + if (!intel_parser.in_offset) + intel_parser.is_mem = 1; + 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; + } + } + } + + /* Not a segment register. Check for register scaling. */ + else if (cur_token.code == '*') + { + if (!intel_parser.in_bracket) + { + as_bad (_("Register scaling only allowed in memory operands")); + return 0; + } + + if (reg->reg_type & Reg16) /* Disallow things like [si*1]. */ + reg = i386_regtab + REGNAM_AX + 4; /* sp is invalid as index */ + else if (i.index_reg) + reg = i386_regtab + REGNAM_EAX + 4; /* esp is invalid as index */ + + /* What follows must be a valid scale. */ + intel_match_token ('*'); + i.index_reg = reg; + i.types[this_operand] |= BaseIndex; + + /* Set the scale after setting the register (otherwise, + i386_scale will complain) */ + if (cur_token.code == '+' || cur_token.code == '-') + { + char *str, sign = cur_token.code; + intel_match_token (cur_token.code); + if (cur_token.code != T_CONST) + { + as_bad (_("Syntax error: Expecting a constant, got `%s'"), + cur_token.str); + return 0; + } + str = (char *) xmalloc (strlen (cur_token.str) + 2); + strcpy (str + 1, cur_token.str); + *str = sign; + if (!i386_scale (str)) + return 0; + free (str); + } + else if (!i386_scale (cur_token.str)) + return 0; + intel_match_token (cur_token.code); + } + + /* 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.in_bracket) + { + + if (!i.base_reg) + i.base_reg = reg; + else if (!i.index_reg) + i.index_reg = reg; + else + { + as_bad (_("Too many register references in memory operand")); + return 0; + } + + i.types[this_operand] |= BaseIndex; + } + + /* It's neither base nor index. */ + else if (!intel_parser.in_offset && !intel_parser.is_mem) + { + i.types[this_operand] |= reg->reg_type & ~BaseIndex; + i.op[this_operand].regs = reg; + i.reg_operands++; + } + else + { + as_bad (_("Invalid use of register")); + return 0; + } + + /* 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.in_offset) + { + char *s = intel_parser.disp; + s += strlen (s) - 1; + if (*s == '+') + *s = '\0'; + } + + return 1; + } + + /* e11 BYTE + | WORD + | DWORD + | FWORD + | QWORD + | TBYTE + | OWORD + | XMMWORD */ + case T_BYTE: + case T_WORD: + case T_DWORD: + case T_FWORD: + case T_QWORD: + case T_TBYTE: + case T_XMMWORD: + intel_match_token (cur_token.code); + + if (cur_token.code == T_PTR) + return 1; + + /* It must have been an identifier. */ + intel_putback_token (); + cur_token.code = T_ID; + /* FALLTHRU */ + + /* e11 id + | constant */ + case T_ID: + if (!intel_parser.in_offset && intel_parser.is_mem <= 0) + { + symbolS *symbolP; + + /* The identifier represents a memory reference only if it's not + preceded by an offset modifier and if it's not an equate. */ + symbolP = symbol_find(cur_token.str); + if (!symbolP || S_GET_SEGMENT(symbolP) != absolute_section) + intel_parser.is_mem = 1; + } + /* FALLTHRU */ + + case T_CONST: + case '-': + case '+': + { + char *save_str, sign = 0; + + /* Allow constants that start with `+' or `-'. */ + if (cur_token.code == '-' || cur_token.code == '+') + { + sign = cur_token.code; + intel_match_token (cur_token.code); + if (cur_token.code != T_CONST) + { + as_bad (_("Syntax error: Expecting a constant, got `%s'"), + cur_token.str); + return 0; + } + } + + save_str = (char *) xmalloc (strlen (cur_token.str) + 2); + strcpy (save_str + !!sign, cur_token.str); + if (sign) + *save_str = sign; + + /* 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) + { + const reg_entry *reg = cur_token.reg; + + if (!intel_parser.in_bracket) + { + as_bad (_("Register scaling only allowed in memory operands")); + return 0; + } + + if (reg->reg_type & Reg16) /* Disallow things like [1*si]. */ + reg = i386_regtab + REGNAM_AX + 4; /* sp is invalid as index */ + else if (i.index_reg) + reg = i386_regtab + REGNAM_EAX + 4; /* esp is invalid as index */ + + /* The constant is followed by `* reg', so it must be + a valid scale. */ + i.index_reg = reg; + i.types[this_operand] |= BaseIndex; + + /* Set the scale after setting the register (otherwise, + i386_scale will complain) */ + if (!i386_scale (save_str)) + return 0; + 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; + } + + /* 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. */ + 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'"), 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 *) xmalloc (strlen (intel_parser.op_string) + 1); + 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 ((reg = parse_register (intel_parser.op_string, &end_op)) != NULL) + { + size_t len = end_op - intel_parser.op_string; + + new_token.code = T_REG; + new_token.reg = reg; + + memcpy (new_token.str, intel_parser.op_string, len); + new_token.str[len] = '\0'; + } + + 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 = '.'; + new_token.str[0] = '.'; + new_token.str[1] = '\0'; + } + else + { + while (is_identifier_char (*q) || *q == '@') + *p++ = *q++; + *p = '\0'; + + if (strcasecmp (new_token.str, "NOT") == 0) + new_token.code = '~'; + + else if (strcasecmp (new_token.str, "MOD") == 0) + new_token.code = '%'; + + else if (strcasecmp (new_token.str, "AND") == 0) + new_token.code = '&'; + + else if (strcasecmp (new_token.str, "OR") == 0) + new_token.code = '|'; + + else if (strcasecmp (new_token.str, "XOR") == 0) + new_token.code = '^'; + + else if (strcasecmp (new_token.str, "SHL") == 0) + new_token.code = T_SHL; + + else if (strcasecmp (new_token.str, "SHR") == 0) + new_token.code = T_SHR; + + else 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, "FWORD") == 0) + new_token.code = T_FWORD; + + else if (strcasecmp (new_token.str, "QWORD") == 0) + new_token.code = T_QWORD; + + else if (strcasecmp (new_token.str, "TBYTE") == 0 + /* XXX remove (gcc still uses it) */ + || strcasecmp (new_token.str, "XWORD") == 0) + new_token.code = T_TBYTE; + + else if (strcasecmp (new_token.str, "XMMWORD") == 0 + || strcasecmp (new_token.str, "OWORD") == 0) + new_token.code = T_XMMWORD; + + 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; + if (*q == ':') + strcat (new_token.str, ":"); + else + as_bad (_("`:' expected")); + } + + else + 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 (strchr ("<>", *intel_parser.op_string) + && *intel_parser.op_string == *(intel_parser.op_string + 1)) + { + new_token.code = *intel_parser.op_string == '<' ? T_SHL : T_SHR; + new_token.str[0] = *intel_parser.op_string; + new_token.str[1] = *intel_parser.op_string; + new_token.str[2] = '\0'; + } + + else + as_bad (_("Unrecognized token `%s'"), 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 () +{ + if (cur_token.code != T_NIL) + { + 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; +} + +int +tc_x86_regname_to_dw2regnum (const char *regname) +{ + unsigned int regnum; + unsigned int regnames_count; + static const char *const regnames_32[] = + { + "eax", "ecx", "edx", "ebx", + "esp", "ebp", "esi", "edi", + "eip", "eflags", NULL, + "st0", "st1", "st2", "st3", + "st4", "st5", "st6", "st7", + NULL, NULL, + "xmm0", "xmm1", "xmm2", "xmm3", + "xmm4", "xmm5", "xmm6", "xmm7", + "mm0", "mm1", "mm2", "mm3", + "mm4", "mm5", "mm6", "mm7", + "fcw", "fsw", "mxcsr", + "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL, + "tr", "ldtr" + }; + static const char *const regnames_64[] = + { + "rax", "rdx", "rcx", "rbx", + "rsi", "rdi", "rbp", "rsp", + "r8", "r9", "r10", "r11", + "r12", "r13", "r14", "r15", + "rip", + "xmm0", "xmm1", "xmm2", "xmm3", + "xmm4", "xmm5", "xmm6", "xmm7", + "xmm8", "xmm9", "xmm10", "xmm11", + "xmm12", "xmm13", "xmm14", "xmm15", + "st0", "st1", "st2", "st3", + "st4", "st5", "st6", "st7", + "mm0", "mm1", "mm2", "mm3", + "mm4", "mm5", "mm6", "mm7", + "rflags", + "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL, + "fs.base", "gs.base", NULL, NULL, + "tr", "ldtr", + "mxcsr", "fcw", "fsw" + }; + const char *const *regnames; + + if (flag_code == CODE_64BIT) + { + regnames = regnames_64; + regnames_count = ARRAY_SIZE (regnames_64); + } + else + { + regnames = regnames_32; + regnames_count = ARRAY_SIZE (regnames_32); + } + + for (regnum = 0; regnum < regnames_count; regnum++) + if (regnames[regnum] != NULL + && strcmp (regname, regnames[regnum]) == 0) + return regnum; + + return -1; +} + +void +tc_x86_frame_initial_instructions (void) +{ + static unsigned int sp_regno; + + if (!sp_regno) + sp_regno = tc_x86_regname_to_dw2regnum (flag_code == CODE_64BIT + ? "rsp" : "esp"); + + cfi_add_CFA_def_cfa (sp_regno, -x86_cie_data_alignment); + cfi_add_CFA_offset (x86_dwarf2_return_column, x86_cie_data_alignment); +} + +int +i386_elf_section_type (const char *str, size_t len) +{ + if (flag_code == CODE_64BIT + && len == sizeof ("unwind") - 1 + && strncmp (str, "unwind", 6) == 0) + return SHT_X86_64_UNWIND; + + return -1; +} + +#ifdef TE_PE +void +tc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size) +{ + expressionS expr; + + expr.X_op = O_secrel; + expr.X_add_symbol = symbol; + expr.X_add_number = 0; + emit_expr (&expr, size); +} +#endif + +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) +/* For ELF on x86-64, add support for SHF_X86_64_LARGE. */ + +int +x86_64_section_letter (int letter, char **ptr_msg) +{ + if (flag_code == CODE_64BIT) + { + if (letter == 'l') + return SHF_X86_64_LARGE; + + *ptr_msg = _("Bad .section directive: want a,l,w,x,M,S,G,T in string"); + } + else + *ptr_msg = _("Bad .section directive: want a,w,x,M,S,G,T in string"); + return -1; +} + +int +x86_64_section_word (char *str, size_t len) +{ + if (len == 5 && flag_code == CODE_64BIT && strncmp (str, "large", 5) == 0) + return SHF_X86_64_LARGE; + + return -1; +} + +static void +handle_large_common (int small ATTRIBUTE_UNUSED) +{ + if (flag_code != CODE_64BIT) + { + s_comm_internal (0, elf_common_parse); + as_warn (_(".largecomm supported only in 64bit mode, producing .comm")); + } + else + { + static segT lbss_section; + asection *saved_com_section_ptr = elf_com_section_ptr; + asection *saved_bss_section = bss_section; + + if (lbss_section == NULL) + { + flagword applicable; + segT seg = now_seg; + subsegT subseg = now_subseg; + + /* The .lbss section is for local .largecomm symbols. */ + lbss_section = subseg_new (".lbss", 0); + applicable = bfd_applicable_section_flags (stdoutput); + bfd_set_section_flags (stdoutput, lbss_section, + applicable & SEC_ALLOC); + seg_info (lbss_section)->bss = 1; + + subseg_set (seg, subseg); + } + + elf_com_section_ptr = &_bfd_elf_large_com_section; + bss_section = lbss_section; + + s_comm_internal (0, elf_common_parse); + + elf_com_section_ptr = saved_com_section_ptr; + bss_section = saved_bss_section; + } +} +#endif /* OBJ_ELF || OBJ_MAYBE_ELF */ diff --git a/contrib/binutils-2.17/gas/config/tc-i386.h b/contrib/binutils-2.17/gas/config/tc-i386.h new file mode 100644 index 0000000000..98517041da --- /dev/null +++ b/contrib/binutils-2.17/gas/config/tc-i386.h @@ -0,0 +1,514 @@ +/* tc-i386.h -- Header file for tc-i386.c + Copyright 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005 + 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, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#ifndef TC_I386 +#define TC_I386 1 + +struct fix; + +#define TARGET_BYTES_BIG_ENDIAN 0 + +#define TARGET_ARCH bfd_arch_i386 +#define TARGET_MACH (i386_mach ()) +extern unsigned long i386_mach (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" +#elif defined (TE_VXWORKS) +#define ELF_TARGET_FORMAT "elf32-i386-vxworks" +#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 + +#define LOCAL_LABELS_FB 1 + +extern const char extra_symbol_chars[]; +#define tc_symbol_chars extra_symbol_chars + +extern const char *i386_comment_chars; +#define tc_comment_chars i386_comment_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' + +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 CpuMMX2 0x1000 /* extended MMX support (with SSE or 3DNow!Ext) required */ +#define CpuSSE 0x2000 /* Streaming SIMD extensions required */ +#define CpuSSE2 0x4000 /* Streaming SIMD extensions 2 required */ +#define Cpu3dnow 0x8000 /* 3dnow! support required */ +#define Cpu3dnowA 0x10000 /* 3dnow!Extensions support required */ +#define CpuSSE3 0x20000 /* Streaming SIMD extensions 3 required */ +#define CpuPNI CpuSSE3 /* Prescott New Instructions required */ +#define CpuPadLock 0x40000 /* VIA PadLock required */ +#define CpuSVME 0x80000 /* AMD Secure Virtual Machine Ext-s required */ +#define CpuVMX 0x100000 /* VMX Instructions required */ +#define CpuMNI 0x200000 /* Merom New Instructions 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|CpuMMX2|CpuSSE|CpuSSE2|CpuPNI|CpuVMX \ + |Cpu3dnow|Cpu3dnowA|CpuK6|CpuAthlon|CpuPadLock|CpuSVME|CpuMNI) + + /* 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 + +#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && !defined (LEX_AT) +#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) x86_cons (EXP, NBYTES) +extern void x86_cons PARAMS ((expressionS *, int)); +#endif + +#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 *)); + +#define DIFF_EXPR_OK /* foo-. gets turned into PC relative relocs */ + +#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_fix 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)) + +extern int i386_parse_name (char *, expressionS *, char *); +#define md_parse_name(s, e, m, c) i386_parse_name (s, e, c) + +extern const struct relax_type md_relax_table[]; +#define TC_GENERIC_RELAX_TABLE md_relax_table + +extern int optimize_align_code; + +#define md_do_align(n, fill, len, max, around) \ +if ((n) \ + && !need_pass_2 \ + && optimize_align_code \ + && (!(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 + +/* We want .cfi_* pseudo-ops for generating unwind info. */ +#define TARGET_USE_CFIPOP 1 + +extern unsigned int x86_dwarf2_return_column; +#define DWARF2_DEFAULT_RETURN_COLUMN x86_dwarf2_return_column + +extern int x86_cie_data_alignment; +#define DWARF2_CIE_DATA_ALIGNMENT x86_cie_data_alignment + +#define tc_regname_to_dw2regnum tc_x86_regname_to_dw2regnum +extern int tc_x86_regname_to_dw2regnum PARAMS ((const char *regname)); + +#define tc_cfi_frame_initial_instructions tc_x86_frame_initial_instructions +extern void tc_x86_frame_initial_instructions PARAMS ((void)); + +#define md_elf_section_type(str,len) i386_elf_section_type (str, len) +extern int i386_elf_section_type PARAMS ((const char *, size_t len)); + +/* Support for SHF_X86_64_LARGE */ +extern int x86_64_section_word PARAMS ((char *, size_t)); +extern int x86_64_section_letter PARAMS ((int letter, char **ptr_msg)); +#define md_elf_section_letter(LETTER, PTR_MSG) x86_64_section_letter (LETTER, PTR_MSG) +#define md_elf_section_word(STR, LEN) x86_64_section_word (STR, LEN) + +#ifdef TE_PE + +#define O_secrel O_md1 + +#define TC_DWARF2_EMIT_OFFSET tc_pe_dwarf2_emit_offset +void tc_pe_dwarf2_emit_offset (symbolS *, unsigned int); + +#endif /* TE_PE */ + +#endif /* TC_I386 */ diff --git a/contrib/binutils-2.17/gas/depend.c b/contrib/binutils-2.17/gas/depend.c new file mode 100644 index 0000000000..4a264aa703 --- /dev/null +++ b/contrib/binutils-2.17/gas/depend.c @@ -0,0 +1,206 @@ +/* depend.c - Handle dependency tracking. + Copyright 1997, 1998, 2000, 2001, 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, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, 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 (FILE *, char *); +static void wrap_output (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 (char *filename) +{ + dep_file = filename; +} + +/* Noticed a new filename, so try to register it. */ + +void +register_dependency (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 *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 (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 (void) +{ + 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.17/gas/doc/as.1 b/contrib/binutils-2.17/gas/doc/as.1 new file mode 100644 index 0000000000..89e3b4c2c7 --- /dev/null +++ b/contrib/binutils-2.17/gas/doc/as.1 @@ -0,0 +1,1109 @@ +.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 +.\" +.\" 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. \*(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- +.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 "AS 1" +.TH AS 1 "2006-06-23" "binutils-2.17" "GNU Development Tools" +.SH "NAME" +AS \- the portable GNU assembler. +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +as [\fB\-a\fR[\fBcdhlns\fR][=\fIfile\fR]] [\fB\-\-alternate\fR] [\fB\-D\fR] + [\fB\-\-defsym\fR \fIsym\fR=\fIval\fR] [\fB\-f\fR] [\fB\-g\fR] [\fB\-\-gstabs\fR] + [\fB\-\-gstabs+\fR] [\fB\-\-gdwarf\-2\fR] [\fB\-\-help\fR] [\fB\-I\fR \fIdir\fR] [\fB\-J\fR] + [\fB\-K\fR] [\fB\-L\fR] [\fB\-\-listing\-lhs\-width\fR=\fI\s-1NUM\s0\fR] + [\fB\-\-listing\-lhs\-width2\fR=\fI\s-1NUM\s0\fR] [\fB\-\-listing\-rhs\-width\fR=\fI\s-1NUM\s0\fR] + [\fB\-\-listing\-cont\-lines\fR=\fI\s-1NUM\s0\fR] [\fB\-\-keep\-locals\fR] [\fB\-o\fR + \fIobjfile\fR] [\fB\-R\fR] [\fB\-\-reduce\-memory\-overheads\fR] [\fB\-\-statistics\fR] + [\fB\-v\fR] [\fB\-version\fR] [\fB\-\-version\fR] [\fB\-W\fR] [\fB\-\-warn\fR] + [\fB\-\-fatal\-warnings\fR] [\fB\-w\fR] [\fB\-x\fR] [\fB\-Z\fR] [\fB@\fR\fI\s-1FILE\s0\fR] + [\fB\-\-target\-help\fR] [\fItarget-options\fR] + [\fB\-\-\fR|\fIfiles\fR ...] +.PP +\&\fITarget Alpha options:\fR + [\fB\-m\fR\fIcpu\fR] + [\fB\-mdebug\fR | \fB\-no\-mdebug\fR] + [\fB\-relax\fR] [\fB\-g\fR] [\fB\-G\fR\fIsize\fR] + [\fB\-F\fR] [\fB\-32addr\fR] +.PP +\&\fITarget \s-1ARC\s0 options:\fR + [\fB\-marc[5|6|7|8]\fR] + [\fB\-EB\fR|\fB\-EL\fR] +.PP +\&\fITarget \s-1ARM\s0 options:\fR + [\fB\-mcpu\fR=\fIprocessor\fR[+\fIextension\fR...]] + [\fB\-march\fR=\fIarchitecture\fR[+\fIextension\fR...]] + [\fB\-mfpu\fR=\fIfloating-point-format\fR] + [\fB\-mfloat\-abi\fR=\fIabi\fR] + [\fB\-meabi\fR=\fIver\fR] + [\fB\-mthumb\fR] + [\fB\-EB\fR|\fB\-EL\fR] + [\fB\-mapcs\-32\fR|\fB\-mapcs\-26\fR|\fB\-mapcs\-float\fR| + \fB\-mapcs\-reentrant\fR] + [\fB\-mthumb\-interwork\fR] [\fB\-k\fR] +.PP +\&\fITarget \s-1CRIS\s0 options:\fR + [\fB\-\-underscore\fR | \fB\-\-no\-underscore\fR] + [\fB\-\-pic\fR] [\fB\-N\fR] + [\fB\-\-emulation=criself\fR | \fB\-\-emulation=crisaout\fR] + [\fB\-\-march=v0_v10\fR | \fB\-\-march=v10\fR | \fB\-\-march=v32\fR | \fB\-\-march=common_v10_v32\fR] +.PP +\&\fITarget D10V options:\fR + [\fB\-O\fR] +.PP +\&\fITarget D30V options:\fR + [\fB\-O\fR|\fB\-n\fR|\fB\-N\fR] +.PP +\&\fITarget i386 options:\fR + [\fB\-\-32\fR|\fB\-\-64\fR] [\fB\-n\fR] +.PP +\&\fITarget i960 options:\fR + [\fB\-ACA\fR|\fB\-ACA_A\fR|\fB\-ACB\fR|\fB\-ACC\fR|\fB\-AKA\fR|\fB\-AKB\fR| + \fB\-AKC\fR|\fB\-AMC\fR] + [\fB\-b\fR] [\fB\-no\-relax\fR] +.PP +\&\fITarget \s-1IA\-64\s0 options:\fR + [\fB\-mconstant\-gp\fR|\fB\-mauto\-pic\fR] + [\fB\-milp32\fR|\fB\-milp64\fR|\fB\-mlp64\fR|\fB\-mp64\fR] + [\fB\-mle\fR|\fBmbe\fR] + [\fB\-mtune=itanium1\fR|\fB\-mtune=itanium2\fR] + [\fB\-munwind\-check=warning\fR|\fB\-munwind\-check=error\fR] + [\fB\-mhint.b=ok\fR|\fB\-mhint.b=warning\fR|\fB\-mhint.b=error\fR] + [\fB\-x\fR|\fB\-xexplicit\fR] [\fB\-xauto\fR] [\fB\-xdebug\fR] +.PP +\&\fITarget \s-1IP2K\s0 options:\fR + [\fB\-mip2022\fR|\fB\-mip2022ext\fR] +.PP +\&\fITarget M32C options:\fR + [\fB\-m32c\fR|\fB\-m16c\fR] +.PP +\&\fITarget M32R options:\fR + [\fB\-\-m32rx\fR|\fB\-\-[no\-]warn\-explicit\-parallel\-conflicts\fR| + \fB\-\-W[n]p\fR] +.PP +\&\fITarget M680X0 options:\fR + [\fB\-l\fR] [\fB\-m68000\fR|\fB\-m68010\fR|\fB\-m68020\fR|...] +.PP +\&\fITarget M68HC11 options:\fR + [\fB\-m68hc11\fR|\fB\-m68hc12\fR|\fB\-m68hcs12\fR] + [\fB\-mshort\fR|\fB\-mlong\fR] + [\fB\-mshort\-double\fR|\fB\-mlong\-double\fR] + [\fB\-\-force\-long\-branchs\fR] [\fB\-\-short\-branchs\fR] + [\fB\-\-strict\-direct\-mode\fR] [\fB\-\-print\-insn\-syntax\fR] + [\fB\-\-print\-opcodes\fR] [\fB\-\-generate\-example\fR] +.PP +\&\fITarget \s-1MCORE\s0 options:\fR + [\fB\-jsri2bsr\fR] [\fB\-sifilter\fR] [\fB\-relax\fR] + [\fB\-mcpu=[210|340]\fR] +.PP +\&\fITarget \s-1MIPS\s0 options:\fR + [\fB\-nocpp\fR] [\fB\-EL\fR] [\fB\-EB\fR] [\fB\-O\fR[\fIoptimization level\fR]] + [\fB\-g\fR[\fIdebug level\fR]] [\fB\-G\fR \fInum\fR] [\fB\-KPIC\fR] [\fB\-call_shared\fR] + [\fB\-non_shared\fR] [\fB\-xgot\fR] + [\fB\-mabi\fR=\fI\s-1ABI\s0\fR] [\fB\-32\fR] [\fB\-n32\fR] [\fB\-64\fR] [\fB\-mfp32\fR] [\fB\-mgp32\fR] + [\fB\-march\fR=\fI\s-1CPU\s0\fR] [\fB\-mtune\fR=\fI\s-1CPU\s0\fR] [\fB\-mips1\fR] [\fB\-mips2\fR] + [\fB\-mips3\fR] [\fB\-mips4\fR] [\fB\-mips5\fR] [\fB\-mips32\fR] [\fB\-mips32r2\fR] + [\fB\-mips64\fR] [\fB\-mips64r2\fR] + [\fB\-construct\-floats\fR] [\fB\-no\-construct\-floats\fR] + [\fB\-trap\fR] [\fB\-no\-break\fR] [\fB\-break\fR] [\fB\-no\-trap\fR] + [\fB\-mfix7000\fR] [\fB\-mno\-fix7000\fR] + [\fB\-mips16\fR] [\fB\-no\-mips16\fR] + [\fB\-mips3d\fR] [\fB\-no\-mips3d\fR] + [\fB\-mdmx\fR] [\fB\-no\-mdmx\fR] + [\fB\-mdsp\fR] [\fB\-mno\-dsp\fR] + [\fB\-mmt\fR] [\fB\-mno\-mt\fR] + [\fB\-mdebug\fR] [\fB\-no\-mdebug\fR] + [\fB\-mpdr\fR] [\fB\-mno\-pdr\fR] +.PP +\&\fITarget \s-1MMIX\s0 options:\fR + [\fB\-\-fixed\-special\-register\-names\fR] [\fB\-\-globalize\-symbols\fR] + [\fB\-\-gnu\-syntax\fR] [\fB\-\-relax\fR] [\fB\-\-no\-predefined\-symbols\fR] + [\fB\-\-no\-expand\fR] [\fB\-\-no\-merge\-gregs\fR] [\fB\-x\fR] + [\fB\-\-linker\-allocated\-gregs\fR] +.PP +\&\fITarget \s-1PDP11\s0 options:\fR + [\fB\-mpic\fR|\fB\-mno\-pic\fR] [\fB\-mall\fR] [\fB\-mno\-extensions\fR] + [\fB\-m\fR\fIextension\fR|\fB\-mno\-\fR\fIextension\fR] + [\fB\-m\fR\fIcpu\fR] [\fB\-m\fR\fImachine\fR] +.PP +\&\fITarget picoJava options:\fR + [\fB\-mb\fR|\fB\-me\fR] +.PP +\&\fITarget PowerPC options:\fR + [\fB\-mpwrx\fR|\fB\-mpwr2\fR|\fB\-mpwr\fR|\fB\-m601\fR|\fB\-mppc\fR|\fB\-mppc32\fR|\fB\-m603\fR|\fB\-m604\fR| + \fB\-m403\fR|\fB\-m405\fR|\fB\-mppc64\fR|\fB\-m620\fR|\fB\-mppc64bridge\fR|\fB\-mbooke\fR| + \fB\-mbooke32\fR|\fB\-mbooke64\fR] + [\fB\-mcom\fR|\fB\-many\fR|\fB\-maltivec\fR] [\fB\-memb\fR] + [\fB\-mregnames\fR|\fB\-mno\-regnames\fR] + [\fB\-mrelocatable\fR|\fB\-mrelocatable\-lib\fR] + [\fB\-mlittle\fR|\fB\-mlittle\-endian\fR|\fB\-mbig\fR|\fB\-mbig\-endian\fR] + [\fB\-msolaris\fR|\fB\-mno\-solaris\fR] +.PP +\&\fITarget \s-1SPARC\s0 options:\fR + [\fB\-Av6\fR|\fB\-Av7\fR|\fB\-Av8\fR|\fB\-Asparclet\fR|\fB\-Asparclite\fR + \fB\-Av8plus\fR|\fB\-Av8plusa\fR|\fB\-Av9\fR|\fB\-Av9a\fR] + [\fB\-xarch=v8plus\fR|\fB\-xarch=v8plusa\fR] [\fB\-bump\fR] + [\fB\-32\fR|\fB\-64\fR] +.PP +\&\fITarget \s-1TIC54X\s0 options:\fR + [\fB\-mcpu=54[123589]\fR|\fB\-mcpu=54[56]lp\fR] [\fB\-mfar\-mode\fR|\fB\-mf\fR] + [\fB\-merrors\-to\-file\fR \fI\fR|\fB\-me\fR \fI\fR] +.PP +\&\fITarget Z80 options:\fR + [\fB\-z80\fR] [\fB\-r800\fR] + [ \fB\-ignore\-undocumented\-instructions\fR] [\fB\-Wnud\fR] + [ \fB\-ignore\-unportable\-instructions\fR] [\fB\-Wnup\fR] + [ \fB\-warn\-undocumented\-instructions\fR] [\fB\-Wud\fR] + [ \fB\-warn\-unportable\-instructions\fR] [\fB\-Wup\fR] + [ \fB\-forbid\-undocumented\-instructions\fR] [\fB\-Fud\fR] + [ \fB\-forbid\-unportable\-instructions\fR] [\fB\-Fup\fR] +.PP +\&\fITarget Xtensa options:\fR + [\fB\-\-[no\-]text\-section\-literals\fR] [\fB\-\-[no\-]absolute\-literals\fR] + [\fB\-\-[no\-]target\-align\fR] [\fB\-\-[no\-]longcalls\fR] + [\fB\-\-[no\-]transform\fR] + [\fB\-\-rename\-section\fR \fIoldname\fR=\fInewname\fR] +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\s-1GNU\s0 \fBas\fR is really a family of assemblers. +If you use (or have used) the \s-1GNU\s0 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 +\&\fIpseudo-ops\fR) and assembler syntax. +.PP +\&\fBas\fR is primarily intended to assemble the output of the +\&\s-1GNU\s0 C compiler \f(CW\*(C`gcc\*(C'\fR for use by the linker +\&\f(CW\*(C`ld\*(C'\fR. Nevertheless, we've tried to make \fBas\fR +assemble correctly everything that other assemblers for the same +machine would assemble. +Any exceptions are documented explicitly. +This doesn't mean \fBas\fR 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. +.PP +Each time you run \fBas\fR it assembles exactly one source +program. The source program is made up of one or more files. +(The standard input is also a file.) +.PP +You give \fBas\fR 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. +.PP +If you give \fBas\fR no file names it attempts to read one input file +from the \fBas\fR standard input, which is normally your terminal. You +may have to type \fBctl-D\fR to tell \fBas\fR there is no more program +to assemble. +.PP +Use \fB\-\-\fR if you need to explicitly name the standard input file +in your command line. +.PP +If the source is empty, \fBas\fR produces a small, empty object +file. +.PP +\&\fBas\fR may write warnings and error messages to the standard error +file (usually your terminal). This should not happen when a compiler +runs \fBas\fR automatically. Warnings report an assumption made so +that \fBas\fR could keep assembling a flawed program; errors report a +grave problem that stops the assembly. +.PP +If you are invoking \fBas\fR via the \s-1GNU\s0 C compiler, +you can use the \fB\-Wa\fR option to pass arguments through to the assembler. +The assembler arguments must be separated from each other (and the \fB\-Wa\fR) +by commas. For example: +.PP +.Vb 1 +\& gcc \-c \-g \-O \-Wa,\-alh,\-L file.c +.Ve +.PP +This passes two options to the assembler: \fB\-alh\fR (emit a listing to +standard output with high-level and assembly source) and \fB\-L\fR (retain +local symbols in the symbol table). +.PP +Usually you do not need to use this \fB\-Wa\fR mechanism, since many compiler +command-line options are automatically passed to the assembler by the compiler. +(You can call the \s-1GNU\s0 compiler driver with the \fB\-v\fR option to see +precisely what options it passes to each compilation pass, including the +assembler.) +.SH "OPTIONS" +.IX Header "OPTIONS" +.IP "\fB@\fR\fIfile\fR" 4 +.IX Item "@file" +Read command-line options from \fIfile\fR. The options read are +inserted in place of the original @\fIfile\fR option. If \fIfile\fR +does not exist, or cannot be read, then the option will be treated +literally, and not removed. +.Sp +Options in \fIfile\fR are separated by whitespace. A whitespace +character may be included in an option by surrounding the entire +option in either single or double quotes. Any character (including a +backslash) may be included by prefixing the character to be included +with a backslash. The \fIfile\fR may itself contain additional +@\fIfile\fR options; any such options will be processed recursively. +.IP "\fB\-a[cdhlmns]\fR" 4 +.IX Item "-a[cdhlmns]" +Turn on listings, in any of a variety of ways: +.RS 4 +.IP "\fB\-ac\fR" 4 +.IX Item "-ac" +omit false conditionals +.IP "\fB\-ad\fR" 4 +.IX Item "-ad" +omit debugging directives +.IP "\fB\-ah\fR" 4 +.IX Item "-ah" +include high-level source +.IP "\fB\-al\fR" 4 +.IX Item "-al" +include assembly +.IP "\fB\-am\fR" 4 +.IX Item "-am" +include macro expansions +.IP "\fB\-an\fR" 4 +.IX Item "-an" +omit forms processing +.IP "\fB\-as\fR" 4 +.IX Item "-as" +include symbols +.IP "\fB=file\fR" 4 +.IX Item "=file" +set the name of the listing file +.RE +.RS 4 +.Sp +You may combine these options; for example, use \fB\-aln\fR for assembly +listing without forms processing. The \fB=file\fR option, if used, must be +the last one. By itself, \fB\-a\fR defaults to \fB\-ahls\fR. +.RE +.IP "\fB\-\-alternate\fR" 4 +.IX Item "--alternate" +Begin in alternate macro mode, see \fBAltmacro,,\f(CB\*(C`.altmacro\*(C'\fB\fR. +.IP "\fB\-D\fR" 4 +.IX Item "-D" +Ignored. This option is accepted for script compatibility with calls to +other assemblers. +.IP "\fB\-\-defsym\fR \fIsym\fR\fB=\fR\fIvalue\fR" 4 +.IX Item "--defsym sym=value" +Define the symbol \fIsym\fR to be \fIvalue\fR before assembling the input file. +\&\fIvalue\fR must be an integer constant. As in C, a leading \fB0x\fR +indicates a hexadecimal value, and a leading \fB0\fR indicates an octal value. +.IP "\fB\-f\fR" 4 +.IX Item "-f" +\&\*(L"fast\*(R"\-\-\-skip whitespace and comment preprocessing (assume source is +compiler output). +.IP "\fB\-g\fR" 4 +.IX Item "-g" +.PD 0 +.IP "\fB\-\-gen\-debug\fR" 4 +.IX Item "--gen-debug" +.PD +Generate debugging information for each assembler source line using whichever +debug format is preferred by the target. This currently means either \s-1STABS\s0, +\&\s-1ECOFF\s0 or \s-1DWARF2\s0. +.IP "\fB\-\-gstabs\fR" 4 +.IX Item "--gstabs" +Generate stabs debugging information for each assembler line. This +may help debugging assembler code, if the debugger can handle it. +.IP "\fB\-\-gstabs+\fR" 4 +.IX Item "--gstabs+" +Generate stabs debugging information for each assembler line, with \s-1GNU\s0 +extensions that probably only gdb can handle, and that could make other +debuggers crash or refuse to read your program. This +may help debugging assembler code. Currently the only \s-1GNU\s0 extension is +the location of the current working directory at assembling time. +.IP "\fB\-\-gdwarf\-2\fR" 4 +.IX Item "--gdwarf-2" +Generate \s-1DWARF2\s0 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. +.IP "\fB\-\-help\fR" 4 +.IX Item "--help" +Print a summary of the command line options and exit. +.IP "\fB\-\-target\-help\fR" 4 +.IX Item "--target-help" +Print a summary of all target specific options and exit. +.IP "\fB\-I\fR \fIdir\fR" 4 +.IX Item "-I dir" +Add directory \fIdir\fR to the search list for \f(CW\*(C`.include\*(C'\fR directives. +.IP "\fB\-J\fR" 4 +.IX Item "-J" +Don't warn about signed overflow. +.IP "\fB\-K\fR" 4 +.IX Item "-K" +Issue warnings when difference tables altered for long displacements. +.IP "\fB\-L\fR" 4 +.IX Item "-L" +.PD 0 +.IP "\fB\-\-keep\-locals\fR" 4 +.IX Item "--keep-locals" +.PD +Keep (in the symbol table) local symbols. On traditional a.out systems +these start with \fBL\fR, but different systems have different local +label prefixes. +.IP "\fB\-\-listing\-lhs\-width=\fR\fInumber\fR" 4 +.IX Item "--listing-lhs-width=number" +Set the maximum width, in words, of the output data column for an assembler +listing to \fInumber\fR. +.IP "\fB\-\-listing\-lhs\-width2=\fR\fInumber\fR" 4 +.IX Item "--listing-lhs-width2=number" +Set the maximum width, in words, of the output data column for continuation +lines in an assembler listing to \fInumber\fR. +.IP "\fB\-\-listing\-rhs\-width=\fR\fInumber\fR" 4 +.IX Item "--listing-rhs-width=number" +Set the maximum width of an input source line, as displayed in a listing, to +\&\fInumber\fR bytes. +.IP "\fB\-\-listing\-cont\-lines=\fR\fInumber\fR" 4 +.IX Item "--listing-cont-lines=number" +Set the maximum number of lines printed in a listing for a single line of input +to \fInumber\fR + 1. +.IP "\fB\-o\fR \fIobjfile\fR" 4 +.IX Item "-o objfile" +Name the object-file output from \fBas\fR \fIobjfile\fR. +.IP "\fB\-R\fR" 4 +.IX Item "-R" +Fold the data section into the text section. +.Sp +Set the default size of \s-1GAS\s0's hash tables to a prime number close to +\&\fInumber\fR. Increasing this value can reduce the length of time it takes the +assembler to perform its tasks, at the expense of increasing the assembler's +memory requirements. Similarly reducing this value can reduce the memory +requirements at the expense of speed. +.IP "\fB\-\-reduce\-memory\-overheads\fR" 4 +.IX Item "--reduce-memory-overheads" +This option reduces \s-1GAS\s0's memory requirements, at the expense of making the +assembly processes slower. Currently this switch is a synonym for +\&\fB\-\-hash\-size=4051\fR, but in the future it may have other effects as well. +.IP "\fB\-\-statistics\fR" 4 +.IX Item "--statistics" +Print the maximum space (in bytes) and total time (in seconds) used by +assembly. +.IP "\fB\-\-strip\-local\-absolute\fR" 4 +.IX Item "--strip-local-absolute" +Remove local absolute symbols from the outgoing symbol table. +.IP "\fB\-v\fR" 4 +.IX Item "-v" +.PD 0 +.IP "\fB\-version\fR" 4 +.IX Item "-version" +.PD +Print the \fBas\fR version. +.IP "\fB\-\-version\fR" 4 +.IX Item "--version" +Print the \fBas\fR version and exit. +.IP "\fB\-W\fR" 4 +.IX Item "-W" +.PD 0 +.IP "\fB\-\-no\-warn\fR" 4 +.IX Item "--no-warn" +.PD +Suppress warning messages. +.IP "\fB\-\-fatal\-warnings\fR" 4 +.IX Item "--fatal-warnings" +Treat warnings as errors. +.IP "\fB\-\-warn\fR" 4 +.IX Item "--warn" +Don't suppress warning messages or treat them as errors. +.IP "\fB\-w\fR" 4 +.IX Item "-w" +Ignored. +.IP "\fB\-x\fR" 4 +.IX Item "-x" +Ignored. +.IP "\fB\-Z\fR" 4 +.IX Item "-Z" +Generate an object file even after errors. +.IP "\fB\-\- |\fR \fIfiles\fR \fB...\fR" 4 +.IX Item "-- | files ..." +Standard input, or source files to assemble. +.PP +The following options are available when as is configured for +an \s-1ARC\s0 processor. +.IP "\fB\-marc[5|6|7|8]\fR" 4 +.IX Item "-marc[5|6|7|8]" +This option selects the core processor variant. +.IP "\fB\-EB | \-EL\fR" 4 +.IX Item "-EB | -EL" +Select either big-endian (\-EB) or little-endian (\-EL) output. +.PP +The following options are available when as is configured for the \s-1ARM\s0 +processor family. +.IP "\fB\-mcpu=\fR\fIprocessor\fR\fB[+\fR\fIextension\fR\fB...]\fR" 4 +.IX Item "-mcpu=processor[+extension...]" +Specify which \s-1ARM\s0 processor variant is the target. +.IP "\fB\-march=\fR\fIarchitecture\fR\fB[+\fR\fIextension\fR\fB...]\fR" 4 +.IX Item "-march=architecture[+extension...]" +Specify which \s-1ARM\s0 architecture variant is used by the target. +.IP "\fB\-mfpu=\fR\fIfloating-point-format\fR" 4 +.IX Item "-mfpu=floating-point-format" +Select which Floating Point architecture is the target. +.IP "\fB\-mfloat\-abi=\fR\fIabi\fR" 4 +.IX Item "-mfloat-abi=abi" +Select which floating point \s-1ABI\s0 is in use. +.IP "\fB\-mthumb\fR" 4 +.IX Item "-mthumb" +Enable Thumb only instruction decoding. +.IP "\fB\-mapcs\-32 | \-mapcs\-26 | \-mapcs\-float | \-mapcs\-reentrant\fR" 4 +.IX Item "-mapcs-32 | -mapcs-26 | -mapcs-float | -mapcs-reentrant" +Select which procedure calling convention is in use. +.IP "\fB\-EB | \-EL\fR" 4 +.IX Item "-EB | -EL" +Select either big-endian (\-EB) or little-endian (\-EL) output. +.IP "\fB\-mthumb\-interwork\fR" 4 +.IX Item "-mthumb-interwork" +Specify that the code has been generated with interworking between Thumb and +\&\s-1ARM\s0 code in mind. +.IP "\fB\-k\fR" 4 +.IX Item "-k" +Specify that \s-1PIC\s0 code has been generated. +.PP +See the info pages for documentation of the CRIS-specific options. +.PP +The following options are available when as is configured for +a D10V processor. +.IP "\fB\-O\fR" 4 +.IX Item "-O" +Optimize output by parallelizing instructions. +.PP +The following options are available when as is configured for a D30V +processor. +.IP "\fB\-O\fR" 4 +.IX Item "-O" +Optimize output by parallelizing instructions. +.IP "\fB\-n\fR" 4 +.IX Item "-n" +Warn when nops are generated. +.IP "\fB\-N\fR" 4 +.IX Item "-N" +Warn when a nop after a 32\-bit multiply instruction is generated. +.PP +The following options are available when as is configured for the +Intel 80960 processor. +.IP "\fB\-ACA | \-ACA_A | \-ACB | \-ACC | \-AKA | \-AKB | \-AKC | \-AMC\fR" 4 +.IX Item "-ACA | -ACA_A | -ACB | -ACC | -AKA | -AKB | -AKC | -AMC" +Specify which variant of the 960 architecture is the target. +.IP "\fB\-b\fR" 4 +.IX Item "-b" +Add code to collect statistics about branches taken. +.IP "\fB\-no\-relax\fR" 4 +.IX Item "-no-relax" +Do not alter compare-and-branch instructions for long displacements; +error if necessary. +.PP +The following options are available when as is configured for the +Ubicom \s-1IP2K\s0 series. +.IP "\fB\-mip2022ext\fR" 4 +.IX Item "-mip2022ext" +Specifies that the extended \s-1IP2022\s0 instructions are allowed. +.IP "\fB\-mip2022\fR" 4 +.IX Item "-mip2022" +Restores the default behaviour, which restricts the permitted instructions to +just the basic \s-1IP2022\s0 ones. +.PP +The following options are available when as is configured for the +Renesas M32C and M16C processors. +.IP "\fB\-m32c\fR" 4 +.IX Item "-m32c" +Assemble M32C instructions. +.IP "\fB\-m16c\fR" 4 +.IX Item "-m16c" +Assemble M16C instructions (the default). +.PP +The following options are available when as is configured for the +Renesas M32R (formerly Mitsubishi M32R) series. +.IP "\fB\-\-m32rx\fR" 4 +.IX 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. +.IP "\fB\-\-warn\-explicit\-parallel\-conflicts or \-\-Wp\fR" 4 +.IX Item "--warn-explicit-parallel-conflicts or --Wp" +Produce warning messages when questionable parallel constructs are +encountered. +.IP "\fB\-\-no\-warn\-explicit\-parallel\-conflicts or \-\-Wnp\fR" 4 +.IX Item "--no-warn-explicit-parallel-conflicts or --Wnp" +Do not produce warning messages when questionable parallel constructs are +encountered. +.PP +The following options are available when as is configured for the +Motorola 68000 series. +.IP "\fB\-l\fR" 4 +.IX Item "-l" +Shorten references to undefined symbols, to one word instead of two. +.IP "\fB\-m68000 | \-m68008 | \-m68010 | \-m68020 | \-m68030\fR" 4 +.IX Item "-m68000 | -m68008 | -m68010 | -m68020 | -m68030" +.PD 0 +.IP "\fB| \-m68040 | \-m68060 | \-m68302 | \-m68331 | \-m68332\fR" 4 +.IX Item "| -m68040 | -m68060 | -m68302 | -m68331 | -m68332" +.IP "\fB| \-m68333 | \-m68340 | \-mcpu32 | \-m5200\fR" 4 +.IX Item "| -m68333 | -m68340 | -mcpu32 | -m5200" +.PD +Specify what processor in the 68000 family is the target. The default +is normally the 68020, but this can be changed at configuration time. +.IP "\fB\-m68881 | \-m68882 | \-mno\-68881 | \-mno\-68882\fR" 4 +.IX 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. +.IP "\fB\-m68851 | \-mno\-68851\fR" 4 +.IX Item "-m68851 | -mno-68851" +The target machine does (or does not) have a memory-management +unit coprocessor. The default is to assume an \s-1MMU\s0 for 68020 and up. +.PP +For details about the \s-1PDP\-11\s0 machine dependent features options, +see \fBPDP\-11\-Options\fR. +.IP "\fB\-mpic | \-mno\-pic\fR" 4 +.IX Item "-mpic | -mno-pic" +Generate position-independent (or position\-dependent) code. The +default is \fB\-mpic\fR. +.IP "\fB\-mall\fR" 4 +.IX Item "-mall" +.PD 0 +.IP "\fB\-mall\-extensions\fR" 4 +.IX Item "-mall-extensions" +.PD +Enable all instruction set extensions. This is the default. +.IP "\fB\-mno\-extensions\fR" 4 +.IX Item "-mno-extensions" +Disable all instruction set extensions. +.IP "\fB\-m\fR\fIextension\fR \fB| \-mno\-\fR\fIextension\fR" 4 +.IX Item "-mextension | -mno-extension" +Enable (or disable) a particular instruction set extension. +.IP "\fB\-m\fR\fIcpu\fR" 4 +.IX Item "-mcpu" +Enable the instruction set extensions supported by a particular \s-1CPU\s0, and +disable all other extensions. +.IP "\fB\-m\fR\fImachine\fR" 4 +.IX Item "-mmachine" +Enable the instruction set extensions supported by a particular machine +model, and disable all other extensions. +.PP +The following options are available when as is configured for +a picoJava processor. +.IP "\fB\-mb\fR" 4 +.IX Item "-mb" +Generate \*(L"big endian\*(R" format output. +.IP "\fB\-ml\fR" 4 +.IX Item "-ml" +Generate \*(L"little endian\*(R" format output. +.PP +The following options are available when as is configured for the +Motorola 68HC11 or 68HC12 series. +.IP "\fB\-m68hc11 | \-m68hc12 | \-m68hcs12\fR" 4 +.IX Item "-m68hc11 | -m68hc12 | -m68hcs12" +Specify what processor is the target. The default is +defined by the configuration option when building the assembler. +.IP "\fB\-mshort\fR" 4 +.IX Item "-mshort" +Specify to use the 16\-bit integer \s-1ABI\s0. +.IP "\fB\-mlong\fR" 4 +.IX Item "-mlong" +Specify to use the 32\-bit integer \s-1ABI\s0. +.IP "\fB\-mshort\-double\fR" 4 +.IX Item "-mshort-double" +Specify to use the 32\-bit double \s-1ABI\s0. +.IP "\fB\-mlong\-double\fR" 4 +.IX Item "-mlong-double" +Specify to use the 64\-bit double \s-1ABI\s0. +.IP "\fB\-\-force\-long\-branchs\fR" 4 +.IX Item "--force-long-branchs" +Relative branches are turned into absolute ones. This concerns +conditional branches, unconditional branches and branches to a +sub routine. +.IP "\fB\-S | \-\-short\-branchs\fR" 4 +.IX Item "-S | --short-branchs" +Do not turn relative branchs into absolute ones +when the offset is out of range. +.IP "\fB\-\-strict\-direct\-mode\fR" 4 +.IX Item "--strict-direct-mode" +Do not turn the direct addressing mode into extended addressing mode +when the instruction does not support direct addressing mode. +.IP "\fB\-\-print\-insn\-syntax\fR" 4 +.IX Item "--print-insn-syntax" +Print the syntax of instruction in case of error. +.IP "\fB\-\-print\-opcodes\fR" 4 +.IX Item "--print-opcodes" +print the list of instructions with syntax and then exit. +.IP "\fB\-\-generate\-example\fR" 4 +.IX Item "--generate-example" +print an example of instruction for each possible instruction and then exit. +This option is only useful for testing \fBas\fR. +.PP +The following options are available when \fBas\fR is configured +for the \s-1SPARC\s0 architecture: +.IP "\fB\-Av6 | \-Av7 | \-Av8 | \-Asparclet | \-Asparclite\fR" 4 +.IX Item "-Av6 | -Av7 | -Av8 | -Asparclet | -Asparclite" +.PD 0 +.IP "\fB\-Av8plus | \-Av8plusa | \-Av9 | \-Av9a\fR" 4 +.IX Item "-Av8plus | -Av8plusa | -Av9 | -Av9a" +.PD +Explicitly select a variant of the \s-1SPARC\s0 architecture. +.Sp +\&\fB\-Av8plus\fR and \fB\-Av8plusa\fR select a 32 bit environment. +\&\fB\-Av9\fR and \fB\-Av9a\fR select a 64 bit environment. +.Sp +\&\fB\-Av8plusa\fR and \fB\-Av9a\fR enable the \s-1SPARC\s0 V9 instruction set with +UltraSPARC extensions. +.IP "\fB\-xarch=v8plus | \-xarch=v8plusa\fR" 4 +.IX Item "-xarch=v8plus | -xarch=v8plusa" +For compatibility with the Solaris v9 assembler. These options are +equivalent to \-Av8plus and \-Av8plusa, respectively. +.IP "\fB\-bump\fR" 4 +.IX Item "-bump" +Warn when the assembler switches to another architecture. +.PP +The following options are available when as is configured for the 'c54x +architecture. +.IP "\fB\-mfar\-mode\fR" 4 +.IX Item "-mfar-mode" +Enable extended addressing mode. All addresses and relocations will assume +extended addressing (usually 23 bits). +.IP "\fB\-mcpu=\fR\fI\s-1CPU_VERSION\s0\fR" 4 +.IX Item "-mcpu=CPU_VERSION" +Sets the \s-1CPU\s0 version being compiled for. +.IP "\fB\-merrors\-to\-file\fR \fI\s-1FILENAME\s0\fR" 4 +.IX Item "-merrors-to-file FILENAME" +Redirect error output to a file, for broken systems which don't support such +behaviour in the shell. +.PP +The following options are available when as is configured for +a \s-1MIPS\s0 processor. +.IP "\fB\-G\fR \fInum\fR" 4 +.IX Item "-G num" +This option sets the largest size of an object that can be referenced +implicitly with the \f(CW\*(C`gp\*(C'\fR register. It is only accepted for targets that +use \s-1ECOFF\s0 format, such as a DECstation running Ultrix. The default value is 8. +.IP "\fB\-EB\fR" 4 +.IX Item "-EB" +Generate \*(L"big endian\*(R" format output. +.IP "\fB\-EL\fR" 4 +.IX Item "-EL" +Generate \*(L"little endian\*(R" format output. +.IP "\fB\-mips1\fR" 4 +.IX Item "-mips1" +.PD 0 +.IP "\fB\-mips2\fR" 4 +.IX Item "-mips2" +.IP "\fB\-mips3\fR" 4 +.IX Item "-mips3" +.IP "\fB\-mips4\fR" 4 +.IX Item "-mips4" +.IP "\fB\-mips5\fR" 4 +.IX Item "-mips5" +.IP "\fB\-mips32\fR" 4 +.IX Item "-mips32" +.IP "\fB\-mips32r2\fR" 4 +.IX Item "-mips32r2" +.IP "\fB\-mips64\fR" 4 +.IX Item "-mips64" +.IP "\fB\-mips64r2\fR" 4 +.IX Item "-mips64r2" +.PD +Generate code for a particular \s-1MIPS\s0 Instruction Set Architecture level. +\&\fB\-mips1\fR is an alias for \fB\-march=r3000\fR, \fB\-mips2\fR is an +alias for \fB\-march=r6000\fR, \fB\-mips3\fR is an alias for +\&\fB\-march=r4000\fR and \fB\-mips4\fR is an alias for \fB\-march=r8000\fR. +\&\fB\-mips5\fR, \fB\-mips32\fR, \fB\-mips32r2\fR, \fB\-mips64\fR, and +\&\fB\-mips64r2\fR +correspond to generic +\&\fB\s-1MIPS\s0 V\fR, \fB\s-1MIPS32\s0\fR, \fB\s-1MIPS32\s0 Release 2\fR, \fB\s-1MIPS64\s0\fR, +and \fB\s-1MIPS64\s0 Release 2\fR +\&\s-1ISA\s0 processors, respectively. +.IP "\fB\-march=\fR\fI\s-1CPU\s0\fR" 4 +.IX Item "-march=CPU" +Generate code for a particular \s-1MIPS\s0 cpu. +.IP "\fB\-mtune=\fR\fIcpu\fR" 4 +.IX Item "-mtune=cpu" +Schedule and tune for a particular \s-1MIPS\s0 cpu. +.IP "\fB\-mfix7000\fR" 4 +.IX Item "-mfix7000" +.PD 0 +.IP "\fB\-mno\-fix7000\fR" 4 +.IX Item "-mno-fix7000" +.PD +Cause nops to be inserted if the read of the destination register +of an mfhi or mflo instruction occurs in the following two instructions. +.IP "\fB\-mdebug\fR" 4 +.IX Item "-mdebug" +.PD 0 +.IP "\fB\-no\-mdebug\fR" 4 +.IX Item "-no-mdebug" +.PD +Cause stabs-style debugging output to go into an ECOFF-style .mdebug +section instead of the standard \s-1ELF\s0 .stabs sections. +.IP "\fB\-mpdr\fR" 4 +.IX Item "-mpdr" +.PD 0 +.IP "\fB\-mno\-pdr\fR" 4 +.IX Item "-mno-pdr" +.PD +Control generation of \f(CW\*(C`.pdr\*(C'\fR sections. +.IP "\fB\-mgp32\fR" 4 +.IX Item "-mgp32" +.PD 0 +.IP "\fB\-mfp32\fR" 4 +.IX Item "-mfp32" +.PD +The register sizes are normally inferred from the \s-1ISA\s0 and \s-1ABI\s0, but these +flags force a certain group of registers to be treated as 32 bits wide at +all times. \fB\-mgp32\fR controls the size of general-purpose registers +and \fB\-mfp32\fR controls the size of floating-point registers. +.IP "\fB\-mips16\fR" 4 +.IX Item "-mips16" +.PD 0 +.IP "\fB\-no\-mips16\fR" 4 +.IX Item "-no-mips16" +.PD +Generate code for the \s-1MIPS\s0 16 processor. This is equivalent to putting +\&\f(CW\*(C`.set mips16\*(C'\fR at the start of the assembly file. \fB\-no\-mips16\fR +turns off this option. +.IP "\fB\-mips3d\fR" 4 +.IX Item "-mips3d" +.PD 0 +.IP "\fB\-no\-mips3d\fR" 4 +.IX Item "-no-mips3d" +.PD +Generate code for the \s-1MIPS\-3D\s0 Application Specific Extension. +This tells the assembler to accept \s-1MIPS\-3D\s0 instructions. +\&\fB\-no\-mips3d\fR turns off this option. +.IP "\fB\-mdmx\fR" 4 +.IX Item "-mdmx" +.PD 0 +.IP "\fB\-no\-mdmx\fR" 4 +.IX Item "-no-mdmx" +.PD +Generate code for the \s-1MDMX\s0 Application Specific Extension. +This tells the assembler to accept \s-1MDMX\s0 instructions. +\&\fB\-no\-mdmx\fR turns off this option. +.IP "\fB\-mdsp\fR" 4 +.IX Item "-mdsp" +.PD 0 +.IP "\fB\-mno\-dsp\fR" 4 +.IX Item "-mno-dsp" +.PD +Generate code for the \s-1DSP\s0 Application Specific Extension. +This tells the assembler to accept \s-1DSP\s0 instructions. +\&\fB\-mno\-dsp\fR turns off this option. +.IP "\fB\-mmt\fR" 4 +.IX Item "-mmt" +.PD 0 +.IP "\fB\-mno\-mt\fR" 4 +.IX Item "-mno-mt" +.PD +Generate code for the \s-1MT\s0 Application Specific Extension. +This tells the assembler to accept \s-1MT\s0 instructions. +\&\fB\-mno\-mt\fR turns off this option. +.IP "\fB\-\-construct\-floats\fR" 4 +.IX Item "--construct-floats" +.PD 0 +.IP "\fB\-\-no\-construct\-floats\fR" 4 +.IX Item "--no-construct-floats" +.PD +The \fB\-\-no\-construct\-floats\fR 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 \fB\-\-construct\-floats\fR is +selected, allowing construction of these floating point constants. +.IP "\fB\-\-emulation=\fR\fIname\fR" 4 +.IX Item "--emulation=name" +This option causes \fBas\fR to emulate \fBas\fR configured +for some other target, in all respects, including output format (choosing +between \s-1ELF\s0 and \s-1ECOFF\s0 only), handling of pseudo-opcodes which may generate +debugging information or store symbol table information, and default +endianness. The available configuration names are: \fBmipsecoff\fR, +\&\fBmipself\fR, \fBmipslecoff\fR, \fBmipsbecoff\fR, \fBmipslelf\fR, +\&\fBmipsbelf\fR. 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 \fBb\fR or \fBl\fR +in the name. Using \fB\-EB\fR or \fB\-EL\fR will override the endianness +selection in any case. +.Sp +This option is currently supported only when the primary target +\&\fBas\fR is configured for is a \s-1MIPS\s0 \s-1ELF\s0 or \s-1ECOFF\s0 target. +Furthermore, the primary target or others specified with +\&\fB\-\-enable\-targets=...\fR 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. +.Sp +Eventually, this option will support more configurations, with more +fine-grained control over the assembler's behavior, and will be supported for +more processors. +.IP "\fB\-nocpp\fR" 4 +.IX Item "-nocpp" +\&\fBas\fR ignores this option. It is accepted for compatibility with +the native tools. +.IP "\fB\-\-trap\fR" 4 +.IX Item "--trap" +.PD 0 +.IP "\fB\-\-no\-trap\fR" 4 +.IX Item "--no-trap" +.IP "\fB\-\-break\fR" 4 +.IX Item "--break" +.IP "\fB\-\-no\-break\fR" 4 +.IX Item "--no-break" +.PD +Control how to deal with multiplication overflow and division by zero. +\&\fB\-\-trap\fR or \fB\-\-no\-break\fR (which are synonyms) take a trap exception +(and only work for Instruction Set Architecture level 2 and higher); +\&\fB\-\-break\fR or \fB\-\-no\-trap\fR (also synonyms, and the default) take a +break exception. +.IP "\fB\-n\fR" 4 +.IX Item "-n" +When this option is used, \fBas\fR will issue a warning every +time it generates a nop instruction from a macro. +.PP +The following options are available when as is configured for +an MCore processor. +.IP "\fB\-jsri2bsr\fR" 4 +.IX Item "-jsri2bsr" +.PD 0 +.IP "\fB\-nojsri2bsr\fR" 4 +.IX Item "-nojsri2bsr" +.PD +Enable or disable the \s-1JSRI\s0 to \s-1BSR\s0 transformation. By default this is enabled. +The command line option \fB\-nojsri2bsr\fR can be used to disable it. +.IP "\fB\-sifilter\fR" 4 +.IX Item "-sifilter" +.PD 0 +.IP "\fB\-nosifilter\fR" 4 +.IX Item "-nosifilter" +.PD +Enable or disable the silicon filter behaviour. By default this is disabled. +The default can be overridden by the \fB\-sifilter\fR command line option. +.IP "\fB\-relax\fR" 4 +.IX Item "-relax" +Alter jump instructions for long displacements. +.IP "\fB\-mcpu=[210|340]\fR" 4 +.IX Item "-mcpu=[210|340]" +Select the cpu type on the target hardware. This controls which instructions +can be assembled. +.IP "\fB\-EB\fR" 4 +.IX Item "-EB" +Assemble for a big endian target. +.IP "\fB\-EL\fR" 4 +.IX Item "-EL" +Assemble for a little endian target. +.PP +See the info pages for documentation of the MMIX-specific options. +.PP +The following options are available when as is configured for +an Xtensa processor. +.IP "\fB\-\-text\-section\-literals | \-\-no\-text\-section\-literals\fR" 4 +.IX Item "--text-section-literals | --no-text-section-literals" +With \fB\-\-text\-section\-literals\fR, literal pools are interspersed +in the text section. The default is +\&\fB\-\-no\-text\-section\-literals\fR, which places literals in a +separate section in the output file. These options only affect literals +referenced via PC-relative \f(CW\*(C`L32R\*(C'\fR instructions; literals for +absolute mode \f(CW\*(C`L32R\*(C'\fR instructions are handled separately. +.IP "\fB\-\-absolute\-literals | \-\-no\-absolute\-literals\fR" 4 +.IX Item "--absolute-literals | --no-absolute-literals" +Indicate to the assembler whether \f(CW\*(C`L32R\*(C'\fR instructions use absolute +or PC-relative addressing. The default is to assume absolute addressing +if the Xtensa processor includes the absolute \f(CW\*(C`L32R\*(C'\fR addressing +option. Otherwise, only the PC-relative \f(CW\*(C`L32R\*(C'\fR mode can be used. +.IP "\fB\-\-target\-align | \-\-no\-target\-align\fR" 4 +.IX 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 \fB\-\-target\-align\fR. +.IP "\fB\-\-longcalls | \-\-no\-longcalls\fR" 4 +.IX Item "--longcalls | --no-longcalls" +Enable or disable transformation of call instructions to allow calls +across a greater range of addresses. The default is +\&\fB\-\-no\-longcalls\fR. +.IP "\fB\-\-transform | \-\-no\-transform\fR" 4 +.IX Item "--transform | --no-transform" +Enable or disable all assembler transformations of Xtensa instructions. +The default is \fB\-\-transform\fR; +\&\fB\-\-no\-transform\fR should be used only in the rare cases when the +instructions must be exactly as specified in the assembly source. +.PP +The following options are available when as is configured for +a Z80 family processor. +.IP "\fB\-z80\fR" 4 +.IX Item "-z80" +Assemble for Z80 processor. +.IP "\fB\-r800\fR" 4 +.IX Item "-r800" +Assemble for R800 processor. +.IP "\fB\-ignore\-undocumented\-instructions\fR" 4 +.IX Item "-ignore-undocumented-instructions" +.PD 0 +.IP "\fB\-Wnud\fR" 4 +.IX Item "-Wnud" +.PD +Assemble undocumented Z80 instructions that also work on R800 without warning. +.IP "\fB\-ignore\-unportable\-instructions\fR" 4 +.IX Item "-ignore-unportable-instructions" +.PD 0 +.IP "\fB\-Wnup\fR" 4 +.IX Item "-Wnup" +.PD +Assemble all undocumented Z80 instructions without warning. +.IP "\fB\-warn\-undocumented\-instructions\fR" 4 +.IX Item "-warn-undocumented-instructions" +.PD 0 +.IP "\fB\-Wud\fR" 4 +.IX Item "-Wud" +.PD +Issue a warning for undocumented Z80 instructions that also work on R800. +.IP "\fB\-warn\-unportable\-instructions\fR" 4 +.IX Item "-warn-unportable-instructions" +.PD 0 +.IP "\fB\-Wup\fR" 4 +.IX Item "-Wup" +.PD +Issue a warning for undocumented Z80 instructions that do notwork on R800. +.IP "\fB\-forbid\-undocumented\-instructions\fR" 4 +.IX Item "-forbid-undocumented-instructions" +.PD 0 +.IP "\fB\-Fud\fR" 4 +.IX Item "-Fud" +.PD +Treat all undocumented instructions as errors. +.IP "\fB\-forbid\-unportable\-instructions\fR" 4 +.IX Item "-forbid-unportable-instructions" +.PD 0 +.IP "\fB\-Fup\fR" 4 +.IX Item "-Fup" +.PD +Treat undocumented Z80 intructions that do notwork on R800 as errors. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIgcc\fR\|(1), \fIld\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 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 \*(L"\s-1GNU\s0 Free Documentation License\*(R". diff --git a/contrib/binutils-2.17/gas/doc/as.texinfo b/contrib/binutils-2.17/gas/doc/as.texinfo new file mode 100644 index 0000000000..6daaed028c --- /dev/null +++ b/contrib/binutils-2.17/gas/doc/as.texinfo @@ -0,0 +1,6760 @@ +\input texinfo @c -*-Texinfo-*- +@c Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +@c 2001, 2002, 2003, 2004, 2005 +@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 --- +@c man begin NAME +@c --- +@include asconfig.texi +@include gasver.texi +@c --- +@c man end +@c --- +@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 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{--alternate}] [@b{-D}] + [@b{--defsym} @var{sym}=@var{val}] [@b{-f}] [@b{-g}] [@b{--gstabs}] + [@b{--gstabs+}] [@b{--gdwarf-2}] [@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{--reduce-memory-overheads}] [@b{--statistics}] + [@b{-v}] [@b{-version}] [@b{--version}] [@b{-W}] [@b{--warn}] + [@b{--fatal-warnings}] [@b{-w}] [@b{-x}] [@b{-Z}] [@b{@@@var{FILE}}] + [@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 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-format}] + [@b{-mfloat-abi}=@var{abi}] + [@b{-meabi}=@var{ver}] + [@b{-mthumb}] + [@b{-EB}|@b{-EL}] + [@b{-mapcs-32}|@b{-mapcs-26}|@b{-mapcs-float}| + @b{-mapcs-reentrant}] + [@b{-mthumb-interwork}] [@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}] + [@b{--march=v0_v10} | @b{--march=v10} | @b{--march=v32} | @b{--march=common_v10_v32}] +@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}] [@b{-n}] +@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{-mtune=itanium1}|@b{-mtune=itanium2}] + [@b{-munwind-check=warning}|@b{-munwind-check=error}] + [@b{-mhint.b=ok}|@b{-mhint.b=warning}|@b{-mhint.b=error}] + [@b{-x}|@b{-xexplicit}] [@b{-xauto}] [@b{-xdebug}] +@end ifset +@ifset IP2K + +@emph{Target IP2K options:} + [@b{-mip2022}|@b{-mip2022ext}] +@end ifset +@ifset M32C + +@emph{Target M32C options:} + [@b{-m32c}|@b{-m16c}] +@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{-O}[@var{optimization level}]] + [@b{-g}[@var{debug level}]] [@b{-G} @var{num}] [@b{-KPIC}] [@b{-call_shared}] + [@b{-non_shared}] [@b{-xgot}] + [@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{-mips64r2}] + [@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{-mdsp}] [@b{-mno-dsp}] + [@b{-mmt}] [@b{-mno-mt}] + [@b{-mdebug}] [@b{-no-mdebug}] + [@b{-mpdr}] [@b{-mno-pdr}] +@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 Z80 + +@emph{Target Z80 options:} + [@b{-z80}] [@b{-r800}] + [@b{ -ignore-undocumented-instructions}] [@b{-Wnud}] + [@b{ -ignore-unportable-instructions}] [@b{-Wnup}] + [@b{ -warn-undocumented-instructions}] [@b{-Wud}] + [@b{ -warn-unportable-instructions}] [@b{-Wup}] + [@b{ -forbid-undocumented-instructions}] [@b{-Fud}] + [@b{ -forbid-unportable-instructions}] [@b{-Fup}] +@end ifset + +@ifset Z8000 +@c Z8000 has no machine-dependent assembler options +@end ifset +@ifset XTENSA + +@emph{Target Xtensa options:} + [@b{--[no-]text-section-literals}] [@b{--[no-]absolute-literals}] + [@b{--[no-]target-align}] [@b{--[no-]longcalls}] + [@b{--[no-]transform}] + [@b{--rename-section} @var{oldname}=@var{newname}] +@end ifset +@c man end +@end smallexample + +@c man begin OPTIONS + +@table @gcctabopt +@include at-file.texi + +@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 --alternate +Begin in alternate macro mode, see @ref{Altmacro,,@code{.altmacro}}. + +@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 -g +@itemx --gen-debug +Generate debugging information for each assembler source line using whichever +debug format is preferred by the target. This currently means either STABS, +ECOFF or DWARF2. + +@item --gstabs +Generate stabs debugging information for each assembler line. This +may help debugging assembler code, if the debugger can handle it. + +@item --gstabs+ +Generate stabs debugging information for each assembler line, with GNU +extensions that probably only gdb can handle, and that could make other +debuggers crash or refuse to read your program. This +may help debugging assembler code. Currently the only GNU extension is +the location of the current working directory at assembling time. + +@item --gdwarf-2 +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. + +@kindex --hash-size=@var{number} +Set the default size of GAS's hash tables to a prime number close to +@var{number}. Increasing this value can reduce the length of time it takes the +assembler to perform its tasks, at the expense of increasing the assembler's +memory requirements. Similarly reducing this value can reduce the memory +requirements at the expense of speed. + +@item --reduce-memory-overheads +This option reduces GAS's memory requirements, at the expense of making the +assembly processes slower. Currently this switch is a synonym for +@samp{--hash-size=4051}, but in the future it may have other effects as well. + +@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 -mfloat-abi=@var{abi} +Select which floating point ABI is in use. +@item -mthumb +Enable Thumb only instruction decoding. +@item -mapcs-32 | -mapcs-26 | -mapcs-float | -mapcs-reentrant +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 M32C +The following options are available when @value{AS} is configured for the +Renesas M32C and M16C processors. + +@table @gcctabopt + +@item -m32c +Assemble M32C instructions. + +@item -m16c +Assemble M16C instructions (the default). + +@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 +@itemx -mips64r2 +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}, @samp{-mips64}, and +@samp{-mips64r2} +correspond to generic +@samp{MIPS V}, @samp{MIPS32}, @samp{MIPS32 Release 2}, @samp{MIPS64}, +and @samp{MIPS64 Release 2} +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 -mpdr +@itemx -mno-pdr +Control generation of @code{.pdr} 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 -mdsp +@itemx -mno-dsp +Generate code for the DSP Application Specific Extension. +This tells the assembler to accept DSP instructions. +@samp{-mno-dsp} turns off this option. + +@item -mmt +@itemx -mno-mt +Generate code for the MT Application Specific Extension. +This tells the assembler to accept MT instructions. +@samp{-mno-mt} 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 --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. These options only affect literals +referenced via PC-relative @code{L32R} instructions; literals for +absolute mode @code{L32R} instructions are handled separately. + +@item --absolute-literals | --no-absolute-literals +Indicate to the assembler whether @code{L32R} instructions use absolute +or PC-relative addressing. The default is to assume absolute addressing +if the Xtensa processor includes the absolute @code{L32R} addressing +option. Otherwise, only the PC-relative @code{L32R} mode can be used. + +@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}. + +@item --transform | --no-transform +Enable or disable all assembler transformations of Xtensa instructions. +The default is @option{--transform}; +@option{--no-transform} should be used only in the rare cases when the +instructions must be exactly as specified in the assembly source. +@end table +@end ifset + +@ifset Z80 +The following options are available when @value{AS} is configured for +a Z80 family processor. +@table @gcctabopt +@item -z80 +Assemble for Z80 processor. +@item -r800 +Assemble for R800 processor. +@item -ignore-undocumented-instructions +@itemx -Wnud +Assemble undocumented Z80 instructions that also work on R800 without warning. +@item -ignore-unportable-instructions +@itemx -Wnup +Assemble all undocumented Z80 instructions without warning. +@item -warn-undocumented-instructions +@itemx -Wud +Issue a warning for undocumented Z80 instructions that also work on R800. +@item -warn-unportable-instructions +@itemx -Wup +Issue a warning for undocumented Z80 instructions that do notwork on R800. +@item -forbid-undocumented-instructions +@itemx -Fud +Treat all undocumented instructions as errors. +@item -forbid-unportable-instructions +@itemx -Fup +Treat undocumented Z80 intructions that do notwork on R800 as errors. +@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 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 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 +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 +* alternate:: --alternate enable alternate macro syntax +* 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 alternate +@section @option{--alternate} + +@kindex --alternate +Begin in alternate macro mode, see @ref{Altmacro,,@code{.altmacro}}. + +@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 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 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 M32C +@samp{#} on the m32c; +@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 VAX +@samp{#} on the Vax; +@end ifset +@ifset Z80 +@samp{;} for the Z80; +@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 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) 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 H8 +(or dollar sign @samp{$}, for the H8/300; or semicolon @samp{;} for the +Renesas SH) +@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, 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 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 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 platform, 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 +@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 +@ifset GENERIC +When generating COFF 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 +@ifset ELF +@ifset GENERIC +When generating ELF output, you +@end ifset +@ifclear GENERIC +You +@end ifclear +can also use the @code{.subsection} directive (@pxref{SubSection}) +to specify a subsection: @samp{.subsection @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}}. In the same way, using a double +equals sign @samp{=}@samp{=} here represents an equivalent of the +@code{.eqv} directive. @xref{Eqv,,@code{.eqv}}. + +@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 SPECIAL-SYMS +@ifset H8 +Symbol names begin with a letter or with one of @samp{._}. On the +Renesas SH 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 + +@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}, @code{.tag}, and @code{.weak} 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 << +@dfn{Shift Left}. Same as the C operator @samp{<<}. + +@item >> +@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 <> +@itemx != +@dfn{Is Not Equal To} +@item < +@dfn{Is Less Than} +@item > +@dfn{Is Greater Than} +@item >= +@dfn{Is Greater Than Or Equal To} +@item <= +@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}} +* Altmacro:: @code{.altmacro} +* 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} } + +* CFI directives:: @code{.cfi_startproc}, @code{.cfi_endproc}, etc. + +* 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}} +* Eqv:: @code{.eqv @var{symbol}, @var{expression}} +* Err:: @code{.err} +* Error:: @code{.error @var{string}} +* 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 + +* Linkonce:: @code{.linkonce [@var{type}]} +* List:: @code{.list} +* Ln:: @code{.ln @var{line-number}} + +* LNS directives:: @code{.file}, @code{.loc}, etc. + +* 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}} +* Noaltmacro:: @code{.noaltmacro} +* 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}} +@end ifset + +* Warning:: @code{.warning @var{string}} +* Weak:: @code{.weak @var{names}} +* Weakref:: @code{.weakref @var{alias}, @var{symbol}} +* 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 arc, hppa, i386 using ELF, i860, iq2000, m68k, or32, +s390, sparc, tic4x, tic80 and xtensa, 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 the tic54x, the +first expression is the alignment request in words. + +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 CFI directives +@section @code{.cfi_startproc} +@cindex @code{cfi_startproc} directive +@code{.cfi_startproc} is used at the beginning of each function that +should have an entry in @code{.eh_frame}. It initializes some internal +data structures and emits architecture dependent initial CFI instructions. +Don't forget to close the function by +@code{.cfi_endproc}. + +@section @code{.cfi_endproc} +@cindex @code{cfi_endproc} directive +@code{.cfi_endproc} is used at the end of a function where it closes its +unwind entry previously opened by +@code{.cfi_startproc}. and emits it to @code{.eh_frame}. + +@section @code{.cfi_def_cfa @var{register}, @var{offset}} +@code{.cfi_def_cfa} defines a rule for computing CFA as: @i{take +address from @var{register} and add @var{offset} to it}. + +@section @code{.cfi_def_cfa_register @var{register}} +@code{.cfi_def_cfa_register} modifies a rule for computing CFA. From +now on @var{register} will be used instead of the old one. Offset +remains the same. + +@section @code{.cfi_def_cfa_offset @var{offset}} +@code{.cfi_def_cfa_offset} modifies a rule for computing CFA. Register +remains the same, but @var{offset} is new. Note that it is the +absolute offset that will be added to a defined register to compute +CFA address. + +@section @code{.cfi_adjust_cfa_offset @var{offset}} +Same as @code{.cfi_def_cfa_offset} but @var{offset} is a relative +value that is added/substracted from the previous offset. + +@section @code{.cfi_offset @var{register}, @var{offset}} +Previous value of @var{register} is saved at offset @var{offset} from +CFA. + +@section @code{.cfi_rel_offset @var{register}, @var{offset}} +Previous value of @var{register} is saved at offset @var{offset} from +the current CFA register. This is transformed to @code{.cfi_offset} +using the known displacement of the CFA register from the CFA. +This is often easier to use, because the number will match the +code it's annotating. + +@section @code{.cfi_signal_frame} +Mark current function as signal trampoline. + +@section @code{.cfi_window_save} +SPARC register window has been saved. + +@section @code{.cfi_escape} @var{expression}[, @dots{}] +Allows the user to add arbitrary bytes to the unwind info. One +might use this to add OS-specific CFI opcodes, or generic CFI +opcodes that GAS does not yet support. + +@node LNS directives +@section @code{.file @var{fileno} @var{filename}} +@cindex @code{file} directive +When emitting dwarf2 line number information @code{.file} assigns filenames +to the @code{.debug_line} file name table. The @var{fileno} operand should +be a unique positive integer to use as the index of the entry in the table. +The @var{filename} operand is a C string literal. + +The detail of filename indicies is exposed to the user because the filename +table is shared with the @code{.debug_info} section of the dwarf2 debugging +information, and thus the user must know the exact indicies that table +entries will have. + +@section @code{.loc @var{fileno} @var{lineno} [@var{column}] [@var{options}]} +@cindex @code{loc} directive +The @code{.loc} directive will add row to the @code{.debug_line} line +number matrix corresponding to the immediately following assembly +instruction. The @var{fileno}, @var{lineno}, and optional @var{column} +arguments will be applied to the @code{.debug_line} state machine before +the row is added. + +The @var{options} are a sequence of the following tokens in any order: + +@table @code +@item basic_block +This option will set the @code{basic_block} register in the +@code{.debug_line} state machine to @code{true}. + +@item prologue_end +This option will set the @code{prologue_end} register in the +@code{.debug_line} state machine to @code{true}. + +@item epilogue_begin +This option will set the @code{epilogue_begin} register in the +@code{.debug_line} state machine to @code{true}. + +@item is_stmt @var{value} +This option will set the @code{is_stmt} register in the +@code{.debug_line} state machine to @code{value}, which must be +either 0 or 1. + +@item isa @var{value} +This directive will set the @code{isa} register in the @code{.debug_line} +state machine to @var{value}, which must be an unsigned integer. + +@end table + +@section @code{.loc_mark_blocks @var{enable}} +@cindex @code{loc_mark_blocks} directive +The @code{.loc_mark_blocks} directive makes the assembler emit an entry +to the @code{.debug_line} line number matrix with the @code{basic_block} +register in the state machine set whenever a code label is seen. +The @var{enable} argument should be either 1 or 0, to enable or disable +this function respectively. + +@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 + +@ifset Z80 +The syntax for @code{equ} on the Z80 is +@samp{@var{symbol} equ @var{expression}}. +On the Z80 it is an eror if @var{symbol} is already defined, +but the symbol is not protected from later redefinition, +compare @xref{Equiv}. +@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 +plus it protects the symbol from later redefinition. + +@node Eqv +@section @code{.eqv @var{symbol}, @var{expression}} +@cindex @code{eqv} directive +The @code{.eqv} directive is like @code{.equiv}, but no attempt is made to +evaluate the expression or any part of it immediately. Instead each time +the resulting symbol is used in an expression, a snapshot of its current +value is taken. + +@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 an error in conditionally compiled code. + +@node Error +@section @code{.error "@var{string}"} +@cindex error directive + +Similarly to @code{.err}, this directive emits an error, but you can specify a +string that will be emitted as the error message. If you don't specify the +message, it defaults to @code{".error directive invoked in source file"}. +@xref{Errors, ,Error and Warning Messages}. + +@smallexample + .error "This code has not been assembled and tested." +@end smallexample + +@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. +@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 is 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. The +behavior of this directive varies depending on the target. When using the +a.out object file format, @command{@value{AS}} simply accepts the directive for +source-file compatibility with existing assemblers, but does not emit anything +for it. When using COFF, comments are emitted to the @code{.comment} or +@code{.rdata} section, depending on the target. When using ELF, comments are +emitted to the @code{.comment} section. + +@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{ifb} directive +@item .ifb @var{text} +Assembles the following section of code if the operand is blank (empty). + +@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{ifnb} directive +@item .ifnb @var{text} +Like @code{.ifb}, but the sense of the test is reversed: this assembles the +following section of code if the operand is non-blank (non-empty). + +@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 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 is 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 + +For some caveats with the spelling of @var{symbol}, see also the discussion +at @xref{Macro}. + +@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 + +For some caveats with the spelling of @var{symbol}, see also the discussion +at @xref{Macro}. + +@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. + +@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 qualify the macro argument to +indicate whether all invocations must specify a non-blank value (through +@samp{:@code{req}}), or whether it takes all of the remaining arguments +(through @samp{:@code{vararg}}). You can supply a default value for any +macro argument by following the name with @samp{=@var{deflt}}. You +cannot define two macros with the same @var{macname} unless it has been +subject to the @code{.purgem} directive (@xref{Purgem}.) between the two +definitions. 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 + +@item .macro m p1:req, p2=0, p3:vararg +Begin the definition of a macro called @code{m}, with at least three +arguments. The first argument must always have a value specified, but +not the second, which instead has a default value. The third formal +will get assigned all remaining arguments specified at invocation time. + +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}. + +Note that since each of the @var{macargs} can be an identifier exactly +as any other one permitted by the target architecture, there may be +occasional problems if the target hand-crafts special meanings to certain +characters when they occur in a special position. For example, if colon +(@code{:}) is generally permitted to be part of a symbol name, but the +architecture specific code special-cases it when occuring as the final +character of a symbol (to denote a label), then the macro parameter +replacement code will have no way of knowing that and consider the whole +construct (including the colon) an identifier, and check only this +identifier for being the subject to parameter substitution. In this +example, besides the potential of just separating identifier and colon +by white space, using alternate macro syntax (@xref{Altmacro}.) and +ampersand (@code{&}) as the character to separate literal text from macro +parameters (or macro parameters from one another) would provide a way to +achieve the same effect: + +@example + .altmacro + .macro label l +l&: + .endm +@end example + +This applies identically to the identifiers used in @code{.irp} (@xref{Irp}.) +and @code{.irpc} (@xref{Irpc}.). + +@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}. + +@item LOCAL @var{name} [ , @dots{} ] +@emph{Warning: @code{LOCAL} is only available if you select ``alternate +macro syntax'' with @samp{--alternate} or @code{.altmacro}.} +@xref{Altmacro,,@code{.altmacro}}. +@end ftable + +@node Altmacro +@section @code{.altmacro} +Enable alternate macro mode, enabling: + +@ftable @code +@item LOCAL @var{name} [ , @dots{} ] +One additional directive, @code{LOCAL}, is available. It is used to +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. + +@item String delimiters +You can write strings delimited in these other ways besides +@code{"@var{string}"}: + +@table @code +@item '@var{string}' +You can delimit strings with single-quote charaters. + +@item <@var{string}> +You can delimit strings with matching angle brackets. +@end table + +@item single-character string escape +To include any single character literally in a string (even if the +character would otherwise have some special meaning), you can prefix the +character with @samp{!} (an exclamation mark). For example, you can +write @samp{<4.3 !> 5.4!!>} to get the literal text @samp{4.3 > 5.4!}. + +@item Expression results as strings +You can write @samp{%@var{expr}} to evaluate the expression @var{expr} +and use the result as a string. +@end ftable + +@node Noaltmacro +@section @code{.noaltmacro} +Disable alternate macro mode. @ref{Altmacro} + +@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 is 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 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{flag_specific_arguments}]]] +@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 +@item G +section is a member of a section group +@item T +section is used for thread-local-storage +@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) +@item @@note +section contains data which is used by things other than the program +@item @@init_array +section contains an array of pointers to init functions +@item @@fini_array +section contains an array of pointers to finish functions +@item @@preinit_array +section contains an array of pointers to pre-init functions +@end table + +Many targets only support the first three section types. + +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 the @code{M} symbol then the @var{type} argument must +be specified as well as an extra argument - @var{entsize} - like this: + +@smallexample +.section @var{name} , "@var{flags}"M, @@@var{type}, @var{entsize} +@end smallexample + +Sections with the @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. @var{entsize} must be an +absolute expression. + +If @var{flags} contains the @code{G} symbol then the @var{type} argument must +be present along with an additional field like this: + +@smallexample +.section @var{name} , "@var{flags}"G, @@@var{type}, @var{GroupName}[, @var{linkage}] +@end smallexample + +The @var{GroupName} field specifies the name of the section group to which this +particular section belongs. The optional linkage field can contain: +@table @code +@item comdat +indicates that only one copy of this section should be retained +@item .gnu.linkonce +an alias for comdat +@end table + +Note - if both the @var{M} and @var{G} flags are present then the fields for +the Merge flag should come first, like this: + +@smallexample +.section @var{name} , "@var{flags}"MG, @@@var{type}, @var{entsize}, @var{GroupName}[, @var{linkage}] +@end smallexample + +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 +@item #tls +section is used for thread local storage +@end table + +This directive replaces the current section and subsection. 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 + +@ifset Z80 +On Z80 @code{set} is a real instruction, use +@samp{@var{symbol} defl @var{expression}} instead. +@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 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} directive +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} directive +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 + +@node Warning +@section @code{.warning "@var{string}"} +@cindex warning directive +Similar to the directive @code{.error} +(@pxref{Error,,@code{.error "@var{string}"}}), but just emits a warning. + +@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. + +On COFF targets other than PE, weak symbols are a GNU extension. 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. + +On the PE target, weak symbols are supported natively as weak aliases. +When a weak symbol is created that is not an alias, GAS creates an +alternate symbol to hold the default value. + +@node Weakref +@section @code{.weakref @var{alias}, @var{target}} + +@cindex @code{weakref} directive +This directive creates an alias to the target symbol that enables the symbol to +be referenced with weak-symbol semantics, but without actually making it weak. +If direct references or definitions of the symbol are present, then the symbol +will not be weak, but if all references to it are through weak references, the +symbol will be marked as weak in the symbol table. + +The effect is equivalent to moving all references to the alias to a separate +assembly source file, renaming the alias to the symbol in it, declaring the +symbol as weak there, and running a reloadable link to merge the object files +resulting from the assembly of the new source file and the old source file that +had the references to the alias removed. + +The alias itself never makes to the symbol table, and is entirely handled +within the assembler. + +@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 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 BFIN +* BFIN-Dependent:: BFIN 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 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 IA64 +* IA-64-Dependent:: Intel IA-64 Dependent Features +@end ifset +@ifset IP2K +* IP2K-Dependent:: IP2K Dependent Features +@end ifset +@ifset M32C +* M32C-Dependent:: M32C 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 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 Z80 +* Z80-Dependent:: Z80 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 ALPHA +@include c-alpha.texi +@end ifset + +@ifset ARC +@include c-arc.texi +@end ifset + +@ifset ARM +@include c-arm.texi +@end ifset + +@ifset BFIN +@include c-bfin.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 +* 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 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 M32C +@include c-m32c.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 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 Z80 +@include c-z80.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 GAS 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 processors (tc-z8k, +tc-h8300), 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 GAS 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.17/gas/doc/asconfig.texi b/contrib/binutils-2.17/gas/doc/asconfig.texi new file mode 100644 index 0000000000..150685f38f --- /dev/null +++ b/contrib/binutils-2.17/gas/doc/asconfig.texi @@ -0,0 +1,90 @@ +@c Copyright 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001, 2002, +@c 2003, 2005 +@c Free Software Foundation, Inc. +@c This file is part of the documentation for the GAS manual + +@c Configuration settings for all-inclusive version of manual + +@c switches:------------------------------------------------------------ +@c Properties of the manual +@c ======================== +@c Discuss all architectures? +@set ALL-ARCH +@c A generic form of manual (not tailored to specific target)? +@set GENERIC +@c Include text on assembler internals? +@clear INTERNALS +@c Many object formats supported in this config? +@set MULTI-OBJ + +@c Object formats of interest +@c ========================== +@set AOUT +@set COFF +@set ELF +@set SOM + +@c CPUs of interest +@c ================ +@set ALPHA +@set ARC +@set ARM +@set BFIN +@set CRIS +@set D10V +@set D30V +@set H8/300 +@set HPPA +@set I370 +@set I80386 +@set I860 +@set I960 +@set IA64 +@set IP2K +@set M32C +@set M32R +@set xc16x +@set M68HC11 +@set M680X0 +@set MCORE +@set MIPS +@set MMIX +@set MS1 +@set MSP430 +@set PDP11 +@set PJ +@set PPC +@set SH +@set SPARC +@set TIC54X +@set V850 +@set VAX +@set XTENSA +@set Z80 +@set Z8000 + +@c Does this version of the assembler use the difference-table kluge? +@set DIFF-TBL-KLUGE + +@c Do all machines described use IEEE floating point? +@clear IEEEFLOAT + +@c Is a word 32 bits, or 16? +@clear W32 +@set W16 + +@c Do symbols have different characters than usual? +@clear SPECIAL-SYMS + +@c strings:------------------------------------------------------------ +@c Name of the assembler: +@set AS as +@c Name of C compiler: +@set GCC gcc +@c Name of linker: +@set LD ld +@c Text for target machine (best not used in generic case; but just in case...) +@set TARGET machine specific +@c Name of object format NOT SET in generic version +@clear OBJ-NAME +@set top_srcdir ../.././gas diff --git a/contrib/binutils-2.17/gas/doc/c-alpha.texi b/contrib/binutils-2.17/gas/doc/c-alpha.texi new file mode 100644 index 0000000000..f426b82282 --- /dev/null +++ b/contrib/binutils-2.17/gas/doc/c-alpha.texi @@ -0,0 +1,472 @@ +@c Copyright 2002, 2003 +@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 Alpha-Dependent +@chapter Alpha Dependent Features +@end ifset + +@ifclear GENERIC +@node Machine Dependencies +@chapter Alpha Dependent Features +@end ifclear + +@cindex Alpha support +@menu +* Alpha Notes:: Notes +* Alpha Options:: Options +* Alpha Syntax:: Syntax +* Alpha Floating Point:: Floating Point +* Alpha Directives:: Alpha Machine Directives +* Alpha Opcodes:: Opcodes +@end menu + +@node Alpha Notes +@section Notes +@cindex Alpha notes +@cindex notes for Alpha + +The documentation here is primarily for the ELF object format. +@code{@value{AS}} also supports the ECOFF and EVAX formats, but +features specific to these formats are not yet documented. + +@node Alpha Options +@section Options +@cindex Alpha options +@cindex options for Alpha + +@table @option +@cindex @code{-m@var{cpu}} command line option, Alpha +@item -m@var{cpu} +This option specifies the target processor. If an attempt is made to +assemble an instruction which will not execute on the target processor, +the assembler may either expand the instruction as a macro or issue an +error message. This option is equivalent to the @code{.arch} directive. + +The following processor names are recognized: +@code{21064}, +@code{21064a}, +@code{21066}, +@code{21068}, +@code{21164}, +@code{21164a}, +@code{21164pc}, +@code{21264}, +@code{21264a}, +@code{21264b}, +@code{ev4}, +@code{ev5}, +@code{lca45}, +@code{ev5}, +@code{ev56}, +@code{pca56}, +@code{ev6}, +@code{ev67}, +@code{ev68}. +The special name @code{all} may be used to allow the assembler to accept +instructions valid for any Alpha processor. + +In order to support existing practice in OSF/1 with respect to @code{.arch}, +and existing practice within @command{MILO} (the Linux ARC bootloader), the +numbered processor names (e.g.@: 21064) enable the processor-specific PALcode +instructions, while the ``electro-vlasic'' names (e.g.@: @code{ev4}) do not. + +@cindex @code{-mdebug} command line option, Alpha +@cindex @code{-no-mdebug} command line option, Alpha +@item -mdebug +@itemx -no-mdebug +Enables or disables the generation of @code{.mdebug} encapsulation for +stabs directives and procedure descriptors. The default is to automatically +enable @code{.mdebug} when the first stabs directive is seen. + +@cindex @code{-relax} command line option, Alpha +@item -relax +This option forces all relocations to be put into the object file, instead +of saving space and resolving some relocations at assembly time. Note that +this option does not propagate all symbol arithmetic into the object file, +because not all symbol arithmetic can be represented. However, the option +can still be useful in specific applications. + +@cindex @code{-g} command line option, Alpha +@item -g +This option is used when the compiler generates debug information. When +@command{gcc} is using @command{mips-tfile} to generate debug +information for ECOFF, local labels must be passed through to the object +file. Otherwise this option has no effect. + +@cindex @code{-G} command line option, Alpha +@item -G@var{size} +A local common symbol larger than @var{size} is placed in @code{.bss}, +while smaller symbols are placed in @code{.sbss}. + +@cindex @code{-F} command line option, Alpha +@cindex @code{-32addr} command line option, Alpha +@item -F +@itemx -32addr +These options are ignored for backward compatibility. +@end table + +@cindex Alpha Syntax +@node Alpha Syntax +@section Syntax +The assembler syntax closely follow the Alpha Reference Manual; +assembler directives and general syntax closely follow the OSF/1 and +OpenVMS syntax, with a few differences for ELF. + +@menu +* Alpha-Chars:: Special Characters +* Alpha-Regs:: Register Names +* Alpha-Relocs:: Relocations +@end menu + +@node Alpha-Chars +@subsection Special Characters + +@cindex line comment character, Alpha +@cindex Alpha line comment character +@samp{#} is the line comment character. + +@cindex line separator, Alpha +@cindex statement separator, Alpha +@cindex Alpha line separator +@samp{;} can be used instead of a newline to separate statements. + +@node Alpha-Regs +@subsection Register Names +@cindex Alpha registers +@cindex register names, Alpha + +The 32 integer registers are referred to as @samp{$@var{n}} or +@samp{$r@var{n}}. In addition, registers 15, 28, 29, and 30 may +be referred to by the symbols @samp{$fp}, @samp{$at}, @samp{$gp}, +and @samp{$sp} respectively. + +The 32 floating-point registers are referred to as @samp{$f@var{n}}. + +@node Alpha-Relocs +@subsection Relocations +@cindex Alpha relocations +@cindex relocations, Alpha + +Some of these relocations are available for ECOFF, but mostly +only for ELF. They are modeled after the relocation format +introduced in Digital Unix 4.0, but there are additions. + +The format is @samp{!@var{tag}} or @samp{!@var{tag}!@var{number}} +where @var{tag} is the name of the relocation. In some cases +@var{number} is used to relate specific instructions. + +The relocation is placed at the end of the instruction like so: + +@example +ldah $0,a($29) !gprelhigh +lda $0,a($0) !gprellow +ldq $1,b($29) !literal!100 +ldl $2,0($1) !lituse_base!100 +@end example + +@table @code +@item !literal +@itemx !literal!@var{N} +Used with an @code{ldq} instruction to load the address of a symbol +from the GOT. + +A sequence number @var{N} is optional, and if present is used to pair +@code{lituse} relocations with this @code{literal} relocation. The +@code{lituse} relocations are used by the linker to optimize the code +based on the final location of the symbol. + +Note that these optimizations are dependent on the data flow of the +program. Therefore, if @emph{any} @code{lituse} is paired with a +@code{literal} relocation, then @emph{all} uses of the register set by +the @code{literal} instruction must also be marked with @code{lituse} +relocations. This is because the original @code{literal} instruction +may be deleted or transformed into another instruction. + +Also note that there may be a one-to-many relationship between +@code{literal} and @code{lituse}, but not a many-to-one. That is, if +there are two code paths that load up the same address and feed the +value to a single use, then the use may not use a @code{lituse} +relocation. + +@item !lituse_base!@var{N} +Used with any memory format instruction (e.g.@: @code{ldl}) to indicate +that the literal is used for an address load. The offset field of the +instruction must be zero. During relaxation, the code may be altered +to use a gp-relative load. + +@item !lituse_jsr!@var{N} +Used with a register branch format instruction (e.g.@: @code{jsr}) to +indicate that the literal is used for a call. During relaxation, the +code may be altered to use a direct branch (e.g.@: @code{bsr}). + +@item !lituse_jsrdirect!@var{N} +Similar to @code{lituse_jsr}, but also that this call cannot be vectored +through a PLT entry. This is useful for functions with special calling +conventions which do not allow the normal call-clobbered registers to be +clobbered. + +@item !lituse_bytoff!@var{N} +Used with a byte mask instruction (e.g.@: @code{extbl}) to indicate +that only the low 3 bits of the address are relevant. During relaxation, +the code may be altered to use an immediate instead of a register shift. + +@item !lituse_addr!@var{N} +Used with any other instruction to indicate that the original address +is in fact used, and the original @code{ldq} instruction may not be +altered or deleted. This is useful in conjunction with @code{lituse_jsr} +to test whether a weak symbol is defined. + +@example +ldq $27,foo($29) !literal!1 +beq $27,is_undef !lituse_addr!1 +jsr $26,($27),foo !lituse_jsr!1 +@end example + +@item !lituse_tlsgd!@var{N} +Used with a register branch format instruction to indicate that the +literal is the call to @code{__tls_get_addr} used to compute the +address of the thread-local storage variable whose descriptor was +loaded with @code{!tlsgd!@var{N}}. + +@item !lituse_tlsldm!@var{N} +Used with a register branch format instruction to indicate that the +literal is the call to @code{__tls_get_addr} used to compute the +address of the base of the thread-local storage block for the current +module. The descriptor for the module must have been loaded with +@code{!tlsldm!@var{N}}. + +@item !gpdisp!@var{N} +Used with @code{ldah} and @code{lda} to load the GP from the current +address, a-la the @code{ldgp} macro. The source register for the +@code{ldah} instruction must contain the address of the @code{ldah} +instruction. There must be exactly one @code{lda} instruction paired +with the @code{ldah} instruction, though it may appear anywhere in +the instruction stream. The immediate operands must be zero. + +@example +bsr $26,foo +ldah $29,0($26) !gpdisp!1 +lda $29,0($29) !gpdisp!1 +@end example + +@item !gprelhigh +Used with an @code{ldah} instruction to add the high 16 bits of a +32-bit displacement from the GP. + +@item !gprellow +Used with any memory format instruction to add the low 16 bits of a +32-bit displacement from the GP. + +@item !gprel +Used with any memory format instruction to add a 16-bit displacement +from the GP. + +@item !samegp +Used with any branch format instruction to skip the GP load at the +target address. The referenced symbol must have the same GP as the +source object file, and it must be declared to either not use @code{$27} +or perform a standard GP load in the first two instructions via the +@code{.prologue} directive. + +@item !tlsgd +@itemx !tlsgd!@var{N} +Used with an @code{lda} instruction to load the address of a TLS +descriptor for a symbol in the GOT. + +The sequence number @var{N} is optional, and if present it used to +pair the descriptor load with both the @code{literal} loading the +address of the @code{__tls_get_addr} function and the @code{lituse_tlsgd} +marking the call to that function. + +For proper relaxation, both the @code{tlsgd}, @code{literal} and +@code{lituse} relocations must be in the same extended basic block. +That is, the relocation with the lowest address must be executed +first at runtime. + +@item !tlsldm +@itemx !tlsldm!@var{N} +Used with an @code{lda} instruction to load the address of a TLS +descriptor for the current module in the GOT. + +Similar in other respects to @code{tlsgd}. + +@item !gotdtprel +Used with an @code{ldq} instruction to load the offset of the TLS +symbol within its module's thread-local storage block. Also known +as the dynamic thread pointer offset or dtp-relative offset. + +@item !dtprelhi +@itemx !dtprello +@itemx !dtprel +Like @code{gprel} relocations except they compute dtp-relative offsets. + +@item !gottprel +Used with an @code{ldq} instruction to load the offset of the TLS +symbol from the thread pointer. Also known as the tp-relative offset. + +@item !tprelhi +@itemx !tprello +@itemx !tprel +Like @code{gprel} relocations except they compute tp-relative offsets. +@end table + +@node Alpha Floating Point +@section Floating Point +@cindex floating point, Alpha (@sc{ieee}) +@cindex Alpha floating point (@sc{ieee}) +The Alpha family uses both @sc{ieee} and VAX floating-point numbers. + +@node Alpha Directives +@section Alpha Assembler Directives + +@command{@value{AS}} for the Alpha supports many additional directives for +compatibility with the native assembler. This section describes them only +briefly. + +@cindex Alpha-only directives +These are the additional directives in @code{@value{AS}} for the Alpha: + +@table @code +@item .arch @var{cpu} +Specifies the target processor. This is equivalent to the +@option{-m@var{cpu}} command-line option. @xref{Alpha Options, Options}, +for a list of values for @var{cpu}. + +@item .ent @var{function}[, @var{n}] +Mark the beginning of @var{function}. An optional number may follow for +compatibility with the OSF/1 assembler, but is ignored. When generating +@code{.mdebug} information, this will create a procedure descriptor for +the function. In ELF, it will mark the symbol as a function a-la the +generic @code{.type} directive. + +@item .end @var{function} +Mark the end of @var{function}. In ELF, it will set the size of the symbol +a-la the generic @code{.size} directive. + +@item .mask @var{mask}, @var{offset} +Indicate which of the integer registers are saved in the current +function's stack frame. @var{mask} is interpreted a bit mask in which +bit @var{n} set indicates that register @var{n} is saved. The registers +are saved in a block located @var{offset} bytes from the @dfn{canonical +frame address} (CFA) which is the value of the stack pointer on entry to +the function. The registers are saved sequentially, except that the +return address register (normally @code{$26}) is saved first. + +This and the other directives that describe the stack frame are +currently only used when generating @code{.mdebug} information. They +may in the future be used to generate DWARF2 @code{.debug_frame} unwind +information for hand written assembly. + +@item .fmask @var{mask}, @var{offset} +Indicate which of the floating-point registers are saved in the current +stack frame. The @var{mask} and @var{offset} parameters are interpreted +as with @code{.mask}. + +@item .frame @var{framereg}, @var{frameoffset}, @var{retreg}[, @var{argoffset}] +Describes the shape of the stack frame. The frame pointer in use is +@var{framereg}; normally this is either @code{$fp} or @code{$sp}. The +frame pointer is @var{frameoffset} bytes below the CFA. The return +address is initially located in @var{retreg} until it is saved as +indicated in @code{.mask}. For compatibility with OSF/1 an optional +@var{argoffset} parameter is accepted and ignored. It is believed to +indicate the offset from the CFA to the saved argument registers. + +@item .prologue @var{n} +Indicate that the stack frame is set up and all registers have been +spilled. The argument @var{n} indicates whether and how the function +uses the incoming @dfn{procedure vector} (the address of the called +function) in @code{$27}. 0 indicates that @code{$27} is not used; 1 +indicates that the first two instructions of the function use @code{$27} +to perform a load of the GP register; 2 indicates that @code{$27} is +used in some non-standard way and so the linker cannot elide the load of +the procedure vector during relaxation. + +@item .usepv @var{function}, @var{which} +Used to indicate the use of the @code{$27} register, similar to +@code{.prologue}, but without the other semantics of needing to +be inside an open @code{.ent}/@code{.end} block. + +The @var{which} argument should be either @code{no}, indicating that +@code{$27} is not used, or @code{std}, indicating that the first two +instructions of the function perform a GP load. + +One might use this directive instead of @code{.prologue} if you are +also using dwarf2 CFI directives. + +@item .gprel32 @var{expression} +Computes the difference between the address in @var{expression} and the +GP for the current object file, and stores it in 4 bytes. In addition +to being smaller than a full 8 byte address, this also does not require +a dynamic relocation when used in a shared library. + +@item .t_floating @var{expression} +Stores @var{expression} as an @sc{ieee} double precision value. + +@item .s_floating @var{expression} +Stores @var{expression} as an @sc{ieee} single precision value. + +@item .f_floating @var{expression} +Stores @var{expression} as a VAX F format value. + +@item .g_floating @var{expression} +Stores @var{expression} as a VAX G format value. + +@item .d_floating @var{expression} +Stores @var{expression} as a VAX D format value. + +@item .set @var{feature} +Enables or disables various assembler features. Using the positive +name of the feature enables while using @samp{no@var{feature}} disables. + +@table @code +@item at +Indicates that macro expansions may clobber the @dfn{assembler +temporary} (@code{$at} or @code{$28}) register. Some macros may not be +expanded without this and will generate an error message if @code{noat} +is in effect. When @code{at} is in effect, a warning will be generated +if @code{$at} is used by the programmer. + +@item macro +Enables the expansion of macro instructions. Note that variants of real +instructions, such as @code{br label} vs @code{br $31,label} are +considered alternate forms and not macros. + +@item move +@itemx reorder +@itemx volatile +These control whether and how the assembler may re-order instructions. +Accepted for compatibility with the OSF/1 assembler, but @command{@value{AS}} +does not do instruction scheduling, so these features are ignored. +@end table +@end table + +The following directives are recognized for compatibility with the OSF/1 +assembler but are ignored. + +@example +.proc .aproc +.reguse .livereg +.option .aent +.ugen .eflag +.alias .noalias +@end example + +@node Alpha Opcodes +@section Opcodes +For detailed information on the Alpha machine instruction set, see the +@c Attempt to work around a very overfull hbox. +@iftex +Alpha Architecture Handbook located at +@smallfonts +@example +ftp://ftp.digital.com/pub/Digital/info/semiconductor/literature/alphaahb.pdf +@end example +@textfonts +@end iftex +@ifnottex +@uref{ftp://ftp.digital.com/pub/Digital/info/semiconductor/literature/alphaahb.pdf,Alpha Architecture Handbook}. +@end ifnottex diff --git a/contrib/binutils-2.17/gas/doc/c-arc.texi b/contrib/binutils-2.17/gas/doc/c-arc.texi new file mode 100644 index 0000000000..04544d1e49 --- /dev/null +++ b/contrib/binutils-2.17/gas/doc/c-arc.texi @@ -0,0 +1,333 @@ +@c Copyright 2000, 2001, 2005 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 ARC-Dependent +@chapter ARC Dependent Features +@end ifset + +@ifclear GENERIC +@node Machine Dependencies +@chapter ARC Dependent Features +@end ifclear + +@set ARC_CORE_DEFAULT 6 + +@cindex ARC support +@menu +* ARC Options:: Options +* ARC Syntax:: Syntax +* ARC Floating Point:: Floating Point +* ARC Directives:: ARC Machine Directives +* ARC Opcodes:: Opcodes +@end menu + + +@node ARC Options +@section Options +@cindex ARC options (none) +@cindex options for ARC (none) + +@table @code + +@cindex @code{-marc[5|6|7|8]} command line option, ARC +@item -marc[5|6|7|8] +This option selects the core processor variant. Using +@code{-marc} is the same as @code{-marc@value{ARC_CORE_DEFAULT}}, which +is also the default. + +@table @code + +@cindex @code{arc5} arc5, ARC +@item arc5 +Base instruction set. + +@cindex @code{arc6} arc6, ARC +@item arc6 +Jump-and-link (jl) instruction. No requirement of an instruction between +setting flags and conditional jump. For example: + +@smallexample + mov.f r0,r1 + beq foo +@end smallexample + +@cindex @code{arc7} arc7, ARC +@item arc7 +Break (brk) and sleep (sleep) instructions. + +@cindex @code{arc8} arc8, ARC +@item arc8 +Software interrupt (swi) instruction. + +@end table + +Note: the @code{.option} directive can to be used to select a core +variant from within assembly code. + +@cindex @code{-EB} command line option, ARC +@item -EB +This option specifies that the output generated by the assembler should +be marked as being encoded for a big-endian processor. + +@cindex @code{-EL} command line option, ARC +@item -EL +This option specifies that the output generated by the assembler should +be marked as being encoded for a little-endian processor - this is the +default. + +@end table + + +@node ARC Syntax +@section Syntax +@menu +* ARC-Chars:: Special Characters +* ARC-Regs:: Register Names +@end menu + +@node ARC-Chars +@subsection Special Characters + +@cindex ARC special characters +@cindex special characters, ARC +*TODO* + +@node ARC-Regs +@subsection Register Names + +@cindex ARC register names +@cindex register names, ARC +*TODO* + + +@node ARC Floating Point +@section Floating Point + +@cindex floating point, ARC (@sc{ieee}) +@cindex ARC floating point (@sc{ieee}) +The ARC core does not currently have hardware floating point +support. Software floating point support is provided by @code{GCC} +and uses @sc{ieee} floating-point numbers. + + +@node ARC Directives +@section ARC Machine Directives + +@cindex machine directives, ARC +@cindex ARC machine directives +The ARC version of @code{@value{AS}} supports the following additional +machine directives: + +@table @code + +@cindex @code{2byte} directive, ARC +@item .2byte @var{expressions} +*TODO* + +@cindex @code{3byte} directive, ARC +@item .3byte @var{expressions} +*TODO* + +@cindex @code{4byte} directive, ARC +@item .4byte @var{expressions} +*TODO* + +@cindex @code{extAuxRegister} directive, ARC +@item .extAuxRegister @var{name},@var{address},@var{mode} +The ARCtangent A4 has extensible auxiliary register space. The +auxiliary registers can be defined in the assembler source code by +using this directive. The first parameter is the @var{name} of the +new auxiallry register. The second parameter is the @var{address} of +the register in the auxiliary register memory map for the variant of +the ARC. The third parameter specifies the @var{mode} in which the +register can be operated is and it can be one of: + +@table @code +@item r (readonly) +@item w (write only) +@item r|w (read or write) +@end table + +For example: + +@smallexample + .extAuxRegister mulhi,0x12,w +@end smallexample + +This specifies an extension auxiliary register called @emph{mulhi} +which is at address 0x12 in the memory space and which is only +writable. + +@cindex @code{extCondCode} directive, ARC +@item .extCondCode @var{suffix},@var{value} +The condition codes on the ARCtangent A4 are extensible and can be +specified by means of this assembler directive. They are specified +by the suffix and the value for the condition code. They can be used to +specify extra condition codes with any values. For example: + +@smallexample + .extCondCode is_busy,0x14 + + add.is_busy r1,r2,r3 + bis_busy _main +@end smallexample + +@cindex @code{extCoreRegister} directive, ARC +@item .extCoreRegister @var{name},@var{regnum},@var{mode},@var{shortcut} +Specifies an extension core register @var{name} for the application. +This allows a register @var{name} with a valid @var{regnum} between 0 +and 60, with the following as valid values for @var{mode} + +@table @samp +@item @emph{r} (readonly) +@item @emph{w} (write only) +@item @emph{r|w} (read or write) +@end table + + +The other parameter gives a description of the register having a +@var{shortcut} in the pipeline. The valid values are: + +@table @code +@item can_shortcut +@item cannot_shortcut +@end table + +For example: + +@smallexample + .extCoreRegister mlo,57,r,can_shortcut +@end smallexample + +This defines an extension core register mlo with the value 57 which +can shortcut the pipeline. + +@cindex @code{extInstruction} directive, ARC +@item .extInstruction @var{name},@var{opcode},@var{subopcode},@var{suffixclass},@var{syntaxclass} +The ARCtangent A4 allows the user to specify extension instructions. +The extension instructions are not macros. The assembler creates +encodings for use of these instructions according to the specification +by the user. The parameters are: + +@table @bullet +@item @var{name} +Name of the extension instruction + +@item @var{opcode} +Opcode to be used. (Bits 27:31 in the encoding). Valid values +0x10-0x1f or 0x03 + +@item @var{subopcode} +Subopcode to be used. Valid values are from 0x09-0x3f. However the +correct value also depends on @var{syntaxclass} + +@item @var{suffixclass} +Determines the kinds of suffixes to be allowed. Valid values are +@code{SUFFIX_NONE}, @code{SUFFIX_COND}, +@code{SUFFIX_FLAG} which indicates the absence or presence of +conditional suffixes and flag setting by the extension instruction. +It is also possible to specify that an instruction sets the flags and +is conditional by using @code{SUFFIX_CODE} | @code{SUFFIX_FLAG}. + +@item @var{syntaxclass} +Determines the syntax class for the instruction. It can have the +following values: + +@table @code +@item @code{SYNTAX_2OP}: +2 Operand Instruction +@item @code{SYNTAX_3OP}: +3 Operand Instruction +@end table + +In addition there could be modifiers for the syntax class as described +below: + +@itemize @minus +Syntax Class Modifiers are: + +@item @code{OP1_MUST_BE_IMM}: +Modifies syntax class SYNTAX_3OP, specifying that the first operand +of a three-operand instruction must be an immediate (i.e. the result +is discarded). OP1_MUST_BE_IMM is used by bitwise ORing it with +SYNTAX_3OP as given in the example below. This could usually be used +to set the flags using specific instructions and not retain results. + +@item @code{OP1_IMM_IMPLIED}: +Modifies syntax class SYNTAX_20P, it specifies that there is an +implied immediate destination operand which does not appear in the +syntax. For example, if the source code contains an instruction like: + +@smallexample +inst r1,r2 +@end smallexample + +it really means that the first argument is an implied immediate (that +is, the result is discarded). This is the same as though the source +code were: inst 0,r1,r2. You use OP1_IMM_IMPLIED by bitwise ORing it +with SYNTAX_20P. + +@end itemize +@end table + +For example, defining 64-bit multiplier with immediate operands: + +@smallexample +.extInstruction mp64,0x14,0x0,SUFFIX_COND | SUFFIX_FLAG , + SYNTAX_3OP|OP1_MUST_BE_IMM +@end smallexample + +The above specifies an extension instruction called mp64 which has 3 operands, +sets the flags, can be used with a condition code, for which the +first operand is an immediate. (Equivalent to discarding the result +of the operation). + +@smallexample + .extInstruction mul64,0x14,0x00,SUFFIX_COND, SYNTAX_2OP|OP1_IMM_IMPLIED +@end smallexample + +This describes a 2 operand instruction with an implicit first +immediate operand. The result of this operation would be discarded. + +@cindex @code{half} directive, ARC +@item .half @var{expressions} +*TODO* + +@cindex @code{long} directive, ARC +@item .long @var{expressions} +*TODO* + +@cindex @code{option} directive, ARC +@item .option @var{arc|arc5|arc6|arc7|arc8} +The @code{.option} directive must be followed by the desired core +version. Again @code{arc} is an alias for +@code{arc@value{ARC_CORE_DEFAULT}}. + +Note: the @code{.option} directive overrides the command line option +@code{-marc}; a warning is emitted when the version is not consistent +between the two - even for the implicit default core version +(arc@value{ARC_CORE_DEFAULT}). + +@cindex @code{short} directive, ARC +@item .short @var{expressions} +*TODO* + +@cindex @code{word} directive, ARC +@item .word @var{expressions} +*TODO* + +@end table + + +@node ARC Opcodes +@section Opcodes + +@cindex ARC opcodes +@cindex opcodes for ARC + +For information on the ARC instruction set, see @cite{ARC Programmers +Reference Manual}, ARC International (www.arc.com) + diff --git a/contrib/binutils-2.17/gas/doc/c-arm.texi b/contrib/binutils-2.17/gas/doc/c-arm.texi new file mode 100644 index 0000000000..ca0998bea6 --- /dev/null +++ b/contrib/binutils-2.17/gas/doc/c-arm.texi @@ -0,0 +1,634 @@ +@c Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 +@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 ARM-Dependent +@chapter ARM Dependent Features +@end ifset + +@ifclear GENERIC +@node Machine Dependencies +@chapter ARM Dependent Features +@end ifclear + +@cindex ARM support +@cindex Thumb support +@menu +* ARM Options:: Options +* ARM Syntax:: Syntax +* ARM Floating Point:: Floating Point +* ARM Directives:: ARM Machine Directives +* ARM Opcodes:: Opcodes +* ARM Mapping Symbols:: Mapping Symbols +@end menu + +@node ARM Options +@section Options +@cindex ARM options (none) +@cindex options for ARM (none) + +@table @code + +@cindex @code{-mcpu=} command line option, ARM +@item -mcpu=@var{processor}[+@var{extension}@dots{}] +This option specifies the target processor. The assembler will issue an +error message if an attempt is made to assemble an instruction which +will not execute on the target processor. The following processor names are +recognized: +@code{arm1}, +@code{arm2}, +@code{arm250}, +@code{arm3}, +@code{arm6}, +@code{arm60}, +@code{arm600}, +@code{arm610}, +@code{arm620}, +@code{arm7}, +@code{arm7m}, +@code{arm7d}, +@code{arm7dm}, +@code{arm7di}, +@code{arm7dmi}, +@code{arm70}, +@code{arm700}, +@code{arm700i}, +@code{arm710}, +@code{arm710t}, +@code{arm720}, +@code{arm720t}, +@code{arm740t}, +@code{arm710c}, +@code{arm7100}, +@code{arm7500}, +@code{arm7500fe}, +@code{arm7t}, +@code{arm7tdmi}, +@code{arm7tdmi-s}, +@code{arm8}, +@code{arm810}, +@code{strongarm}, +@code{strongarm1}, +@code{strongarm110}, +@code{strongarm1100}, +@code{strongarm1110}, +@code{arm9}, +@code{arm920}, +@code{arm920t}, +@code{arm922t}, +@code{arm940t}, +@code{arm9tdmi}, +@code{arm9e}, +@code{arm926e}, +@code{arm926ej-s}, +@code{arm946e-r0}, +@code{arm946e}, +@code{arm946e-s}, +@code{arm966e-r0}, +@code{arm966e}, +@code{arm966e-s}, +@code{arm968e-s}, +@code{arm10t}, +@code{arm10tdmi}, +@code{arm10e}, +@code{arm1020}, +@code{arm1020t}, +@code{arm1020e}, +@code{arm1022e}, +@code{arm1026ej-s}, +@code{arm1136j-s}, +@code{arm1136jf-s}, +@code{arm1156t2-s}, +@code{arm1156t2f-s}, +@code{arm1176jz-s}, +@code{arm1176jzf-s}, +@code{mpcore}, +@code{mpcorenovfp}, +@code{cortex-a8}, +@code{cortex-r4}, +@code{cortex-m3}, +@code{ep9312} (ARM920 with Cirrus Maverick coprocessor), +@code{i80200} (Intel XScale processor) +@code{iwmmxt} (Intel(r) XScale processor with Wireless MMX(tm) technology coprocessor) +and +@code{xscale}. +The special name @code{all} may be used to allow the +assembler to accept instructions valid for any ARM processor. + +In addition to the basic instruction set, the assembler can be told to +accept various extension mnemonics that extend the processor using the +co-processor instruction space. For example, @code{-mcpu=arm920+maverick} +is equivalent to specifying @code{-mcpu=ep9312}. The following extensions +are currently supported: +@code{+maverick} +@code{+iwmmxt} +and +@code{+xscale}. + +@cindex @code{-march=} command line option, ARM +@item -march=@var{architecture}[+@var{extension}@dots{}] +This option specifies the target architecture. The assembler will issue +an error message if an attempt is made to assemble an instruction which +will not execute on the target architecture. The following architecture +names are recognized: +@code{armv1}, +@code{armv2}, +@code{armv2a}, +@code{armv2s}, +@code{armv3}, +@code{armv3m}, +@code{armv4}, +@code{armv4xm}, +@code{armv4t}, +@code{armv4txm}, +@code{armv5}, +@code{armv5t}, +@code{armv5txm}, +@code{armv5te}, +@code{armv5texp}, +@code{armv6}, +@code{armv6j}, +@code{armv6k}, +@code{armv6z}, +@code{armv6zk}, +@code{armv7}, +@code{armv7a}, +@code{armv7r}, +@code{armv7m}, +@code{iwmmxt} +and +@code{xscale}. +If both @code{-mcpu} and +@code{-march} are specified, the assembler will use +the setting for @code{-mcpu}. + +The architecture option can be extended with the same instruction set +extension options as the @code{-mcpu} option. + +@cindex @code{-mfpu=} command line option, ARM +@item -mfpu=@var{floating-point-format} + +This option specifies the floating point format to assemble for. The +assembler will issue an error message if an attempt is made to assemble +an instruction which will not execute on the target floating point unit. +The following format options are recognized: +@code{softfpa}, +@code{fpe}, +@code{fpe2}, +@code{fpe3}, +@code{fpa}, +@code{fpa10}, +@code{fpa11}, +@code{arm7500fe}, +@code{softvfp}, +@code{softvfp+vfp}, +@code{vfp}, +@code{vfp10}, +@code{vfp10-r0}, +@code{vfp9}, +@code{vfpxd}, +@code{arm1020t}, +@code{arm1020e}, +@code{arm1136jf-s} +and +@code{maverick}. + +In addition to determining which instructions are assembled, this option +also affects the way in which the @code{.double} assembler directive behaves +when assembling little-endian code. + +The default is dependent on the processor selected. For Architecture 5 or +later, the default is to assembler for VFP instructions; for earlier +architectures the default is to assemble for FPA instructions. + +@cindex @code{-mthumb} command line option, ARM +@item -mthumb +This option specifies that the assembler should start assembling Thumb +instructions; that is, it should behave as though the file starts with a +@code{.code 16} directive. + +@cindex @code{-mthumb-interwork} command line option, ARM +@item -mthumb-interwork +This option specifies that the output generated by the assembler should +be marked as supporting interworking. + +@cindex @code{-mapcs} command line option, ARM +@item -mapcs @code{[26|32]} +This option specifies that the output generated by the assembler should +be marked as supporting the indicated version of the Arm Procedure. +Calling Standard. + +@cindex @code{-matpcs} command line option, ARM +@item -matpcs +This option specifies that the output generated by the assembler should +be marked as supporting the Arm/Thumb Procedure Calling Standard. If +enabled this option will cause the assembler to create an empty +debugging section in the object file called .arm.atpcs. Debuggers can +use this to determine the ABI being used by. + +@cindex @code{-mapcs-float} command line option, ARM +@item -mapcs-float +This indicates the floating point variant of the APCS should be +used. In this variant floating point arguments are passed in FP +registers rather than integer registers. + +@cindex @code{-mapcs-reentrant} command line option, ARM +@item -mapcs-reentrant +This indicates that the reentrant variant of the APCS should be used. +This variant supports position independent code. + +@cindex @code{-mfloat-abi=} command line option, ARM +@item -mfloat-abi=@var{abi} +This option specifies that the output generated by the assembler should be +marked as using specified floating point ABI. +The following values are recognized: +@code{soft}, +@code{softfp} +and +@code{hard}. + +@cindex @code{-eabi=} command line option, ARM +@item -meabi=@var{ver} +This option specifies which EABI version the produced object files should +conform to. +The following values are recognised: +@code{gnu}, +@code{4} +and +@code{5}. + +@cindex @code{-EB} command line option, ARM +@item -EB +This option specifies that the output generated by the assembler should +be marked as being encoded for a big-endian processor. + +@cindex @code{-EL} command line option, ARM +@item -EL +This option specifies that the output generated by the assembler should +be marked as being encoded for a little-endian processor. + +@cindex @code{-k} command line option, ARM +@cindex PIC code generation for ARM +@item -k +This option specifies that the output of the assembler should be marked +as position-independent code (PIC). + +@end table + + +@node ARM Syntax +@section Syntax +@menu +* ARM-Chars:: Special Characters +* ARM-Regs:: Register Names +@end menu + +@node ARM-Chars +@subsection Special Characters + +@cindex line comment character, ARM +@cindex ARM line comment character +The presence of a @samp{@@} on a line indicates the start of a comment +that extends to the end of the current line. If a @samp{#} appears as +the first character of a line, the whole line is treated as a comment. + +@cindex line separator, ARM +@cindex statement separator, ARM +@cindex ARM line separator +The @samp{;} character can be used instead of a newline to separate +statements. + +@cindex immediate character, ARM +@cindex ARM immediate character +Either @samp{#} or @samp{$} can be used to indicate immediate operands. + +@cindex identifiers, ARM +@cindex ARM identifiers +*TODO* Explain about /data modifier on symbols. + +@node ARM-Regs +@subsection Register Names + +@cindex ARM register names +@cindex register names, ARM +*TODO* Explain about ARM register naming, and the predefined names. + +@node ARM Floating Point +@section Floating Point + +@cindex floating point, ARM (@sc{ieee}) +@cindex ARM floating point (@sc{ieee}) +The ARM family uses @sc{ieee} floating-point numbers. + + + +@node ARM Directives +@section ARM Machine Directives + +@cindex machine directives, ARM +@cindex ARM machine directives +@table @code + +@cindex @code{align} directive, ARM +@item .align @var{expression} [, @var{expression}] +This is the generic @var{.align} directive. For the ARM however if the +first argument is zero (ie no alignment is needed) the assembler will +behave as if the argument had been 2 (ie pad to the next four byte +boundary). This is for compatibility with ARM's own assembler. + +@cindex @code{req} directive, ARM +@item @var{name} .req @var{register name} +This creates an alias for @var{register name} called @var{name}. For +example: + +@smallexample + foo .req r0 +@end smallexample + +@cindex @code{unreq} directive, ARM +@item .unreq @var{alias-name} +This undefines a register alias which was previously defined using the +@code{req} directive. For example: + +@smallexample + foo .req r0 + .unreq foo +@end smallexample + +An error occurs if the name is undefined. Note - this pseudo op can +be used to delete builtin in register name aliases (eg 'r0'). This +should only be done if it is really necessary. + +@cindex @code{code} directive, ARM +@item .code @code{[16|32]} +This directive selects the instruction set being generated. The value 16 +selects Thumb, with the value 32 selecting ARM. + +@cindex @code{thumb} directive, ARM +@item .thumb +This performs the same action as @var{.code 16}. + +@cindex @code{arm} directive, ARM +@item .arm +This performs the same action as @var{.code 32}. + +@cindex @code{force_thumb} directive, ARM +@item .force_thumb +This directive forces the selection of Thumb instructions, even if the +target processor does not support those instructions + +@cindex @code{thumb_func} directive, ARM +@item .thumb_func +This directive specifies that the following symbol is the name of a +Thumb encoded function. This information is necessary in order to allow +the assembler and linker to generate correct code for interworking +between Arm and Thumb instructions and should be used even if +interworking is not going to be performed. The presence of this +directive also implies @code{.thumb} + +@cindex @code{thumb_set} directive, ARM +@item .thumb_set +This performs the equivalent of a @code{.set} directive in that it +creates a symbol which is an alias for another symbol (possibly not yet +defined). This directive also has the added property in that it marks +the aliased symbol as being a thumb function entry point, in the same +way that the @code{.thumb_func} directive does. + +@cindex @code{.ltorg} directive, ARM +@item .ltorg +This directive causes the current contents of the literal pool to be +dumped into the current section (which is assumed to be the .text +section) at the current location (aligned to a word boundary). +@code{GAS} maintains a separate literal pool for each section and each +sub-section. The @code{.ltorg} directive will only affect the literal +pool of the current section and sub-section. At the end of assembly +all remaining, un-empty literal pools will automatically be dumped. + +Note - older versions of @code{GAS} would dump the current literal +pool any time a section change occurred. This is no longer done, since +it prevents accurate control of the placement of literal pools. + +@cindex @code{.pool} directive, ARM +@item .pool +This is a synonym for .ltorg. + +@cindex @code{.fnstart} directive, ARM +@item .unwind_fnstart +Marks the start of a function with an unwind table entry. + +@cindex @code{.fnend} directive, ARM +@item .unwind_fnend +Marks the end of a function with an unwind table entry. The unwind index +table entry is created when this directive is processed. + +If no personality routine has been specified then standard personality +routine 0 or 1 will be used, depending on the number of unwind opcodes +required. + +@cindex @code{.cantunwind} directive, ARM +@item .cantunwind +Prevents unwinding through the current function. No personality routine +or exception table data is required or permitted. + +@cindex @code{.personality} directive, ARM +@item .personality @var{name} +Sets the personality routine for the current function to @var{name}. + +@cindex @code{.personalityindex} directive, ARM +@item .personalityindex @var{index} +Sets the personality routine for the current function to the EABI standard +routine number @var{index} + +@cindex @code{.handlerdata} directive, ARM +@item .handlerdata +Marks the end of the current function, and the start of the exception table +entry for that function. Anything between this directive and the +@code{.fnend} directive will be added to the exception table entry. + +Must be preceded by a @code{.personality} or @code{.personalityindex} +directive. + +@cindex @code{.save} directive, ARM +@item .save @var{reglist} +Generate unwinder annotations to restore the registers in @var{reglist}. +The format of @var{reglist} is the same as the corresponding store-multiple +instruction. + +@smallexample +@exdent @emph{core registers} + .save @{r4, r5, r6, lr@} + stmfd sp!, @{r4, r5, r6, lr@} +@exdent @emph{FPA registers} + .save f4, 2 + sfmfd f4, 2, [sp]! +@exdent @emph{VFP registers} + .save @{d8, d9, d10@} + fstmdf sp!, @{d8, d9, d10@} +@exdent @emph{iWMMXt registers} + .save @{wr10, wr11@} + wstrd wr11, [sp, #-8]! + wstrd wr10, [sp, #-8]! +or + .save wr11 + wstrd wr11, [sp, #-8]! + .save wr10 + wstrd wr10, [sp, #-8]! +@end smallexample + +@cindex @code{.pad} directive, ARM +@item .pad #@var{count} +Generate unwinder annotations for a stack adjustment of @var{count} bytes. +A positive value indicates the function prologue allocated stack space by +decrementing the stack pointer. + +@cindex @code{.movsp} directive, ARM +@item .movsp @var{reg} +Tell the unwinder that @var{reg} contains the current stack pointer. + +@cindex @code{.setfp} directive, ARM +@item .setfp @var{fpreg}, @var{spreg} [, #@var{offset}] +Make all unwinder annotations relaive to a frame pointer. Without this +the unwinder will use offsets from the stack pointer. + +The syntax of this directive is the same as the @code{sub} or @code{mov} +instruction used to set the frame pointer. @var{spreg} must be either +@code{sp} or mentioned in a previous @code{.movsp} directive. + +@smallexample +.movsp ip +mov ip, sp +@dots{} +.setfp fp, ip, #4 +sub fp, ip, #4 +@end smallexample + +@cindex @code{.unwind_raw} directive, ARM +@item .raw @var{offset}, @var{byte1}, @dots{} +Insert one of more arbitary unwind opcode bytes, which are known to adjust +the stack pointer by @var{offset} bytes. + +For example @code{.unwind_raw 4, 0xb1, 0x01} is equivalent to +@code{.save @{r0@}} + +@cindex @code{.cpu} directive, ARM +@item .cpu @var{name} +Select the target processor. Valid values for @var{name} are the same as +for the @option{-mcpu} commandline option. + +@cindex @code{.arch} directive, ARM +@item .arch @var{name} +Select the target architecture. Valid values for @var{name} are the same as +for the @option{-march} commandline option. + +@cindex @code{.fpu} directive, ARM +@item .fpu @var{name} +Select the floating point unit to assemble for. Valid values for @var{name} +are the same as for the @option{-mfpu} commandline option. + +@cindex @code{.eabi_attribute} directive, ARM +@item .eabi_attribute @var{tag}, @var{value} +Set the EABI object attribute number @var{tag} to @var{value}. The value +is either a @code{number}, @code{"string"}, or @code{number, "string"} +depending on the tag. + +@end table + +@node ARM Opcodes +@section Opcodes + +@cindex ARM opcodes +@cindex opcodes for ARM +@code{@value{AS}} implements all the standard ARM opcodes. It also +implements several pseudo opcodes, including several synthetic load +instructions. + +@table @code + +@cindex @code{NOP} pseudo op, ARM +@item NOP +@smallexample + nop +@end smallexample + +This pseudo op will always evaluate to a legal ARM instruction that does +nothing. Currently it will evaluate to MOV r0, r0. + +@cindex @code{LDR reg,=